From a67fa274f7205e87df2f7512f1192924c65f4fae Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 5 Apr 2018 17:09:15 +0300 Subject: [PATCH 01/88] temp commit... in progress with new DOS operators and VM #135, #117, #67 --- .../src/manager/plugins/organisms/Config.js | 16 +- .../manager/plugins/organisms/Organisms.js | 2 +- .../plugins/organisms/dos/Code2String.js | 3 +- .../plugins/organisms/dos/Operators.js | 181 ++++--- .../plugins/organisms/dos/Organisms.js | 9 - client/src/vm/Operators.js | 473 +++++++++++++++++- client/src/vm/VM.js | 49 +- common/src/FastArray.js | 22 +- 8 files changed, 604 insertions(+), 151 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 931954f..2137632 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -47,16 +47,16 @@ const Config = { * {Boolean} If turned on, then organism will be responsible for changing * mutations probabilities. Otherwise these probabilities will be constant */ - orgMutationProbsPerOrg: true, + orgMutationProbsPerOrg: false, /** * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 3000, + orgCloneMinAge: 300, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 20000000, + orgCloneMinEnergy: 200000, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -74,7 +74,7 @@ const Config = { * do mutations according to orgRainMutationPercent config. If 0, then * mutations wilsabled. Should be less then ORGANISM_MAX_MUTATION_PERIOD */ - orgRainMutationPeriod: 100, + orgRainMutationPeriod: 500, /** * {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%) @@ -85,7 +85,7 @@ const Config = { * own mutations period and percent. false - mean, that these values will be * constant for all organisms */ - orgRainPerOrg: true, + orgRainPerOrg: false, /** * {Number} Amount of iterations, after which crossover will be applied * to random organisms. May be set to 0 to turn crossover off @@ -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: 0, + orgAlivePeriod: 1000000, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, @@ -157,12 +157,12 @@ 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: 3, /** * {Number} Amount of bits for storing operator. This is first XX bits * in a number. */ - codeBitsPerOperator: 8, + codeBitsPerOperator: 5, /** * {Number} Amount of bits, which stores maximum block length. Under block * length we mean maximum amount of lines in one block like if, for,... diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 28e0631..243bb64 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -177,7 +177,7 @@ class Organisms extends Configurable { while (org = item && item.val) { org.run(); - this.onOrganism(org); + //this.onOrganism(org); item = item.next; } diff --git a/client/src/manager/plugins/organisms/dos/Code2String.js b/client/src/manager/plugins/organisms/dos/Code2String.js index 139b0f4..51c7642 100644 --- a/client/src/manager/plugins/organisms/dos/Code2String.js +++ b/client/src/manager/plugins/organisms/dos/Code2String.js @@ -62,7 +62,8 @@ class Code2String { */ this._offsets = [0]; - Num.init(this._OPERATORS_CB_LEN); + // TODO: fix this + Num.init(12);//this._OPERATORS_CB_LEN); this._BITS_AFTER_ONE_VAR = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR; this._BITS_AFTER_TWO_VARS = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR * 2; diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index e99548c..a4e0cb5 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -17,102 +17,117 @@ const Num = require('./../../../../vm/Num'); * much faster, then Helper.normalize() */ const IN_WORLD = Helper.inWorld; -const IS_FINITE = Number.isFinite; -const IS_NAN = Number.isNaN; -/** - * {Function} Just a shortcuts - */ -const FOUR_BITS = 4; -const CONDITION_BITS = 2; -const MAX_VAL = Number.MAX_VALUE; -/** - * {Array} Available conditions for if operator. Amount should be - * the same like (1 << Num.BITS_PER_VAR) - */ -const CONDITIONS = [(a,b)=>aa>b, (a,b)=>a===b, (a,b)=>a!==b]; -/** - * {Array} Available operators for math calculations - */ -const OPERATORS = [ - (a,b) => {const v=a+b; return IS_FINITE(v)?v:MAX_VAL}, - (a,b) => {const v=a-b; return IS_FINITE(v)?v:-MAX_VAL}, - (a,b) => {const v=a*b; return IS_FINITE(v)?v:MAX_VAL}, - (a,b) => {const v=a/b; return IS_FINITE(v)?v:MAX_VAL}, - (a,b) => {const v=a%b; return IS_NAN(v)?0:v}, - (a,b) => a&b, - (a,b) => a|b, - (a,b) => a^b, - (a,b) => a>>b, - (a,b) => a< a>>>b, - (a,b) => +(a +(a>b), - (a,b) => +(a===b), - (a,b) => +(a!==b), - (a,b) => +(a<=b) -]; class OperatorsDos extends Operators { + static compile() { + const bitsPerOp = OConfig.codeBitsPerOperator; + // + // IMPORTANT: don't use super here, because it breaks Operators + // IMPORTANT: class internal logic. Operators.global will be point + // IMPORTANT: to the Window + // + Operators.compile(12); + + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); + + this._compileLookAt(); + } + + /** + * Compiles all variants of lookAt operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx xx 4 + * number: 01011 xxxxx 00 01 00 01... + * string: v0 = lookAt(v1, v0) + */ + static _compileLookAt() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + for (let v2 = 0; v2 < vars; v2++) { + eval(`OperatorsDos.global.fn = function (line) { + const vars = this.vars; + const x = (vars[${v1}] + .5) << 0; + const y = (vars[${v2}] + .5) << 0; + vars[${v0}] = (IN_WORLD(x, y) ? (this._positions[x][y] <= 0 ? this._world.data[x][y] : this._positions[x][y].energy) : 0); + return ++line; + }`); + ops[h(`${'01011'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}`)] = this.global.fn; + } + } + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** * {Object} These operator handlers should return next script line * number VM should step to + * TODO: will be removed */ - this._OPERATORS_CB = [ - this.onVar.bind(this), - this.onConst.bind(this), - this.onCondition.bind(this), - this.onLoop.bind(this), - this.onOperator.bind(this), - this.onLookAt.bind(this), - this.onEatLeft.bind(this), - this.onEatRight.bind(this), - this.onEatUp.bind(this), - this.onEatDown.bind(this), - this.onStepLeft.bind(this), - this.onStepRight.bind(this), - this.onStepUp.bind(this), - this.onStepDown.bind(this), - this.onFromMem.bind(this), - this.onToMem.bind(this), - this.onMyX.bind(this), - this.onMyY.bind(this), - this.onCheckLeft.bind(this), - this.onCheckRight.bind(this), - this.onCheckUp.bind(this), - this.onCheckDown.bind(this) - ]; + // this._OPERATORS_CB = [ + // this.onVar.bind(this), + // this.onConst.bind(this), + // this.onCondition.bind(this), + // this.onLoop.bind(this), + // this.onOperator.bind(this), + // this.onLookAt.bind(this), + // this.onEatLeft.bind(this), + // this.onEatRight.bind(this), + // this.onEatUp.bind(this), + // this.onEatDown.bind(this), + // this.onStepLeft.bind(this), + // this.onStepRight.bind(this), + // this.onStepUp.bind(this), + // this.onStepDown.bind(this), + // this.onFromMem.bind(this), + // this.onToMem.bind(this), + // this.onMyX.bind(this), + // this.onMyY.bind(this), + // this.onCheckLeft.bind(this), + // this.onCheckRight.bind(this), + // this.onCheckUp.bind(this), + // this.onCheckDown.bind(this) + // ]; /** * {Object} Reusable object to pass it as a parameter to this.fire(..., ret) + * TODO: should be removed, because this class should have references to world, organisms, positions,... */ - this._ret = {ret: 0}; - // - // We have to set amount of available operators for correct - // working of mutations of operators. - // - Num.init(this._OPERATORS_CB.length); - - this._BITS_AFTER_ONE_VAR = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR; - this._BITS_AFTER_TWO_VARS = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR * 2; - this._BITS_AFTER_THREE_VARS = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR * 3; + this._ret = {ret: 0}; + /** + * {Observer} Observer for sending external events + */ + this._obs = obs; + this._world = man.world; + this._organisms = man.organisms; + this._positions = man.positions; } destroy() { super.destroy(); - this._OPERATORS_CB = null; + + this._world = null; + this._organisms = null; + this._positions = null; + this._obs = null; this._ret = null; } - get operators() {return this._OPERATORS_CB} - /** * Handler of variable assignment operator. 'xx' means, that amount of * bits depends on configuration. '...' means, that all other bits are * ignored. Example: * bits : 8 xx xx * number: 00000000 00 01... - * desc : var v0 v1 + * desc : var v0 v1 * string: v0 = v1 * * @param {Number} num One bit packed byte code row @@ -208,7 +223,7 @@ class OperatorsDos extends Operators { const y = (vars[Num.getVar2(num)] + .5) << 0; if (IN_WORLD(x, y)) { - this.obs.fire(EVENTS.GET_ENERGY, x, y, this._ret); + this._obs.fire(EVENTS.GET_ENERGY, x, y, this._ret); vars[Num.getVar0(num)] = this._ret.ret; return ++line; } @@ -223,7 +238,7 @@ class OperatorsDos extends Operators { const ret = this._ret; ret.ret = amount; - this.obs.fire(EVENTS.EAT, org, org.x - 1, org.y, ret); + this._obs.fire(EVENTS.EAT, org, org.x - 1, org.y, ret); org.energy += ret.ret; this.vars[Num.getVar0(num)] = ret.ret; @@ -235,7 +250,7 @@ class OperatorsDos extends Operators { const ret = this._ret; ret.ret = amount; - this.obs.fire(EVENTS.EAT, org, org.x + 1, org.y, ret); + this._obs.fire(EVENTS.EAT, org, org.x + 1, org.y, ret); org.energy += ret.ret; this.vars[Num.getVar0(num)] = ret.ret; @@ -247,7 +262,7 @@ class OperatorsDos extends Operators { const ret = this._ret; ret.ret = amount; - this.obs.fire(EVENTS.EAT, org, org.x, org.y - 1, ret); + this._obs.fire(EVENTS.EAT, org, org.x, org.y - 1, ret); org.energy += ret.ret; this.vars[Num.getVar0(num)] = ret.ret; @@ -259,7 +274,7 @@ class OperatorsDos extends Operators { const ret = this._ret; ret.ret = amount; - this.obs.fire(EVENTS.EAT, org, org.x, org.y + 1, ret); + this._obs.fire(EVENTS.EAT, org, org.x, org.y + 1, ret); org.energy += ret.ret; this.vars[Num.getVar0(num)] = ret.ret; @@ -296,28 +311,28 @@ class OperatorsDos extends Operators { onMyY(num, line, org) {this.vars[Num.getVar0(num)] = org.y; return ++line} onCheckLeft(num, line, org) { - this.obs.fire(EVENTS.CHECK_AT, org.x - 1, org.y, this._ret); + 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._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._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._obs.fire(EVENTS.CHECK_AT, org.x, org.y + 1, this._ret); this.vars[Num.getVar0(num)] = this._ret.ret; return ++line; } _step(org, x1, y1, x2, y2, step) { - this.obs.fire(EVENTS.STEP, org, x1, y1, x2, y2); + this._obs.fire(EVENTS.STEP, org, x1, y1, x2, y2); return org.x === x2 && org.y === y2 ? step : 0; } @@ -345,4 +360,6 @@ class OperatorsDos extends Operators { } } +OperatorsDos.compile(); + module.exports = OperatorsDos; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 659788d..46bd79c 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -96,7 +96,6 @@ class Organisms extends BaseOrganisms { addOrgHandlers(org) { super.addOrgHandlers(org); - org.on(EVENTS.GET_ENERGY, this._onGetEnergy.bind(this)); org.on(EVENTS.EAT, this._onEat.bind(this)); org.on(EVENTS.STEP, this._onStep.bind(this)); org.on(EVENTS.CHECK_AT, this._onCheckAt.bind(this)); @@ -112,14 +111,6 @@ class Organisms extends BaseOrganisms { return new Organism(...args); } - _onGetEnergy(x, y, ret) { - if (this.positions[x][y] <= 0) { - ret.ret = this.world.getDot(x, y) - } else { - ret.ret = this.positions[x][y].energy; - } - } - _onEat(org, x, y, ret) { const eat = ret.ret; [x, y] = NORMALIZE_NO_DIR(x, y); diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index ffff580..12e4a62 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -4,34 +4,489 @@ * * @author flatline */ +const OConfig = require('./../manager/plugins/organisms/Config'); +const Num = require('./Num'); + class Operators { - constructor(offs, vars, obs) { + /** + * Compiles all variants of bite-code to speed up the execution. + * @param {Number} operators Amount of operators + */ + static compile(operators = 11) { + const bitsPerOp = OConfig.codeBitsPerOperator; + const MAX_BITS = 32; + /** + * {Object} Container for storing of dynamic operator handlers + */ + this.global = typeof window === 'undefined' ? global : window; + /** + * {Number} Bit related constants + */ + this.FOUR_BITS = 4; + this.CONDITION_BITS = 2; + this.FUNC_NAME_BITS = 10; + /** + * {Array} Available conditions for if operator + */ + this._CONDITIONS = ['<', '>', '===', '!==']; + /** + * {Array} Available operators for math calculations + */ + this._OPERATORS = [ + (a,b,c) => `const v=this.vars[${b}] + this.vars[${c}]; this.vars[${a}]=Number.isFinite(v) ? v : Number.MAX_VALUE`, + (a,b,c) => `const v=this.vars[${b}] - this.vars[${c}]; this.vars[${a}]=Number.isFinite(v) ? v :-Number.MAX_VALUE`, + (a,b,c) => `const v=this.vars[${b}] * this.vars[${c}]; this.vars[${a}]=Number.isFinite(v) ? v : Number.MAX_VALUE`, + (a,b,c) => `const v=this.vars[${b}] / this.vars[${c}]; this.vars[${a}]=Number.isFinite(v) ? v : Number.MAX_VALUE`, + (a,b,c) => `const v=this.vars[${b}] % this.vars[${c}]; this.vars[${a}]=Number.isNaN(v) ? 0 : v`, + (a,b,c) => `this.vars[${a}] = this.vars[${b}] & this.vars[${c}]`, + (a,b,c) => `this.vars[${a}] = this.vars[${b}] | this.vars[${c}]`, + (a,b,c) => `this.vars[${a}] = this.vars[${b}] ^ this.vars[${c}]`, + (a,b,c) => `this.vars[${a}] = this.vars[${b}] >> this.vars[${c}]`, + (a,b,c) => `this.vars[${a}] = this.vars[${b}] << this.vars[${c}]`, + (a,b,c) => `this.vars[${a}] = this.vars[${b}] >>> this.vars[${c}]`, + (a,b,c) => `this.vars[${a}] = +(this.vars[${b}] < this.vars[${c}])`, + (a,b,c) => `this.vars[${a}] = +(this.vars[${b}] > this.vars[${c}])`, + (a,b,c) => `this.vars[${a}] = +(this.vars[${b}] === this.vars[${c}])`, + (a,b,c) => `this.vars[${a}] = +(this.vars[${b}] !== this.vars[${c}])`, + (a,b,c) => `this.vars[${a}] = +(this.vars[${b}] <= this.vars[${c}])` + ]; + /** + * {Array} Array of lengths of commands. Every item of this array contains + * length of operator's data, which follows after len bits in byte-code number. + * The size of this array is equal to amount of operators. Child classes may + * append items to it. + */ + this.LENS = [ + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2), // var + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar), // const + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2 + this.CONDITION_BITS), // if + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2 + this.CONDITION_BITS), // loop + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3 + this.FOUR_BITS), // math + MAX_BITS - (bitsPerOp), // func + MAX_BITS - (bitsPerOp), // func call + MAX_BITS - (bitsPerOp), // return + MAX_BITS - (bitsPerOp), // bracket + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2), // toMem + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2) // fromMem + ]; + /** + * {Object} Map for all available operator handlers + */ + this._compiledOperators = {}; + // + // IMPORTANT: don't change callbacks order + // This section compiles all possible variants of operators and their + // arguments. This is how we dramatically speed up byte-code interpretation + // + Num.init(operators); + this._compileVar(); + this._compileConst(); + this._compileIf(); + this._compileLoop(); + this._compileOperator(); + this._compileFunc(); + this._compileFuncCall(); + this._compileReturn(); + this._compileBracket(); + this._compileToMem(); + this._compileFromMem(); + } + + /** + * Converts string BIN number representation into number. Removes spaces. + * @param {String} s BIN string. e.g.: 'aa bb cc' -> 0xaabbcc + * @param {Number} width Amount of digits in binary number + * @returns {Number} + */ + static _toHexNum(s, width = 0) { + return parseInt(s.split(' ').join('').padStart(width, '0'), 2) + } + + /** + * Converts number to binary string + * @param {Number} n Number to convert + * @param {Number} width Amount of digits in binary number + * @return {String} Binary string + */ + static _toBinStr(n, width = 0) { + return n.toString(2).padStart(width, '0'); + } + + /** + * Compiles all variants of var operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx + * number: 00000 xxxxx 00 01... + * string: v0 = v1 + */ + static _compileVar() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function (line) { + this.vars[${v0}] = this.vars[${v1}]; + return ++line; + }`); + ops[h(`${'00000'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + } + } + } + + /** + * Compiles all variants of const operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx + * number: 000001 xxxxx 00 01... + * string: v0 = 1 + */ + static _compileConst() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const bits = Num.MAX_BITS - OConfig.codeConstBits; + const bits1var = Num.BITS_OF_VAR0; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function (line, num) { + this.vars[${v0}] = num << ${bits1var} >>> ${bits}; + return ++line; + }`); + ops[h(`${'00001'}${b(v0, bpv)}`)] = this.global.fn; + } + } + + /** + * Compiles all variants of if operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx 2 + * number: 00010 xxxxx 00 01 00... + * string: if (v0 < v1) { + */ + static _compileIf() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let c = 0; c < Math.pow(2, this.CONDITION_BITS); c++) { + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function (line) { + if (this.vars[${v0}] ${this._CONDITIONS[c]} this.vars[${v1}]) {return ++line} + return this.offs[line]; + }`); + ops[h(`${'00010'}${b(v0, bpv)}${b(v1, bpv)}${b(c, this.CONDITION_BITS)}`)] = this.global.fn; + } + } + } + } + + /** + * Compiles all variants of while operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx 2 + * number: 00011 xxxxx 00 01 00... + * string: while (v0 < v1) { + */ + static _compileLoop() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let c = 0; c < Math.pow(2, this.CONDITION_BITS); c++) { + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function (line) { + if (this.vars[${v0}] ${this._CONDITIONS[c]} this.vars[${v1}]) {return ++line} + return this.offs[line]; + }`); + ops[h(`${'00011'}${b(v0, bpv)}${b(v1, bpv)}${b(c, this.CONDITION_BITS)}`)] = this.global.fn; + } + } + } + } + + /** + * Compiles all variants of math operators and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx xx 4 + * number: 00100 xxxxx 00 01 00 01... + * string: v0 = v1 - v0 + */ + static _compileOperator() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let op = 0; op < Math.pow(2, this.FOUR_BITS); op++) { + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + for (let v2 = 0; v2 < vars; v2++) { + eval(`Operators.global.fn = function (line) { + ${this._OPERATORS[op](v0, v1, v2)} + return ++line; + }`); + ops[h(`${'00100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}${b(op, this.FOUR_BITS)}`)] = this.global.fn; + } + } + } + } + } + + /** + * Compiles all variants of function operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Function name consists of 10 bits. Example: + * + * bits : 5 5 10 + * number: 00101 xxxxx 0000000001... + * string: func n + */ + static _compileFunc() { + const ops = this._compiledOperators; + const h = this._toHexNum; + + eval(`Operators.global.fn = function (line) {return this.offs[line]}`); + ops[h(`${'00101'}`)] = this.global.fn; + } + + /** + * Compiles all variants of function call operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Function name consists of 10 bits. Example: + * + * bits : 5 5 10 + * number: 00110 xxxxx 0000000001... + * string: call n + */ + static _compileFuncCall() { + const ops = this._compiledOperators; + const h = this._toHexNum; + const bits = Num.MAX_BITS - this.FUNC_NAME_BITS; + const opBits = Num.BITS_PER_OPERATOR; + + eval(`Operators.global.fn = function (line, num) { + const offs = this.funcs[num << ${opBits} >>> ${bits}]; + if (typeof offs !== 'undefined') { + this.stack.push(line + 1); + this.stack.push(this.vars.slice()); + return offs; + } + return ++line; + }`); + ops[h(`${'00110'}`)] = this.global.fn; + } + + /** + * Compiles all variants of return operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 + * number: 00111 xxxxx... + * string: return + */ + static _compileReturn() { + const ops = this._compiledOperators; + const h = this._toHexNum; + const vars = Math.pow(2, OConfig.codeBitsPerVar); + + eval(`Operators.global.fn = function (line) { + if (this.stack.length > 0) { + const stackVars = this.stack.pop(); + const vars = this.vars; + for (let i = 0; i < ${vars}; i++) {vars[i] = stackVars[i]} + return this.stack.pop(); + } + return 0; + }`); + ops[h(`${'00111'}`)] = this.global.fn; + } + + /** + * Compiles all variants of } operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 + * number: 01000 xxxxx... + * string: } + */ + static _compileBracket() { + const ops = this._compiledOperators; + const h = this._toHexNum; + const vars = Math.pow(2, OConfig.codeBitsPerVar); + + eval(`Operators.global.fn = function (line, num, org, lines) { + const operator = lines[this.offs[line]] >>> Num.VAR_BITS_OFFS; + if (operator === 0x3) {return this.offs[line]} // loop + if (operator === 0x5) { // func + const stackVars = this.stack.pop(); + const vars = this.vars; + for (let i = 0; i < ${vars}; i++) {vars[i] = stackVars[i]} + return this.stack.pop(); + } + return ++line; + }`); + ops[h(`${'01000'}`)] = this.global.fn; + } + + /** + * Compiles all variants of toMem operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx + * number: 01001 xxxxx 00 01... + * string: toMem(v0, v1) + */ + static _compileToMem() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + const memLen = Math.pow(2, OConfig.orgMemBits); + + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function (line, num, org) { + const offs = ((this.vars[${v0}] + .5) << 0) >>> 0; + org.mem[offs >= ${memLen} ? ${memLen-1} : offs] = this.vars[${v1}]; + return ++line; + }`); + ops[h(`${'01001'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + } + } + } + + /** + * Compiles all variants of toMem operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 5 5 xx xx + * number: 01010 xxxxx 00 01... + * string: v0 = fromMem(v1) + */ + static _compileFromMem() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + const memLen = Math.pow(2, OConfig.orgMemBits); + + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function (line, num, org) { + const offs = ((this.vars[${v1}] + .5) << 0) >>> 0; + this.vars[${v0}] = org.mem[offs >= ${memLen} ? ${memLen-1} : offs]; + return ++line; + }`); + ops[h(`${'01010'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + } + } + } + + constructor(offs, vars) { /** * {Array} Array of offsets for closing braces. For 'for', 'if' * and other operators. */ - this.offs = offs; + this.offs = offs; /** * {Array} Available variables */ - this.vars = vars; + this.vars = vars; /** - * {Observer} Observer for sending external events + * {Object} Handlers map, which handle every variant of byte-code */ - this.obs = obs; + this._OPERATORS_CB = Operators._compiledOperators; + this.lens = Operators.LENS; + this.stack = []; + this.funcs = []; + } + + /** + * Updates indexes of if, while, func,... in byte-code after any mutation + * @param {Array} code Byte-code + */ + updateIndexes(code) { + const len = code.length; + const varOffs = Num.VAR_BITS_OFFS; + const offs = this.offs; + const funcs = this.funcs = []; + const blocks = []; + + for (let i = 0; i < len; i++) { + const operator = code[i] >>> varOffs; + if (operator === 0x2 || operator === 0x3) { // if, while + offs[i] = i + 1; + blocks.push(i); + continue; + } + if (operator === 0x5) { // func + offs[i] = i + 1; + funcs.push(i + 1); + blocks.push(i); + continue; + } + if (operator === 0x8) { // bracket + if (blocks.length > 0) { + offs[i] = blocks.pop(); + offs[offs[i]] = i + 1; + } + } + } } destroy() { - this.offs = null; - this.vars = null; - this.obs = null; + this.funcs = null; + this.stack = null; + this._OPERATORS_CB = null; + this.offs = null; + this.vars = null; } /** * Returns operators array. Should be overridden in child class * @abstract */ - get operators() {return []} + get operators() {return this._OPERATORS_CB} /** * Sets offsets array from outside diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index df075bd..24e6f41 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -12,6 +12,7 @@ const Observer = require('./../../../common/src/Observer'); const OConfig = require('./../manager/plugins/organisms/Config'); const EVENTS = require('./../../src/share/Events').EVENTS; const EVENT_AMOUNT = require('./../../src/share/Events').EVENT_AMOUNT; +const Operators = require('./Operators'); const Num = require('./Num'); /** * {Number} Maximum stack size, which may be used for recursion or function parameters @@ -38,14 +39,14 @@ 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() || [21490344, 4865568, 1105425628, 46244285, 1428694332, 42772605, 11546049, 117239988, 46244285, 1338608526, 20072550]; this._line = parent && parent.line || 0; /** * {Array} Array of two numbers. first - line number where we have * to return if first line appears. second - line number, where ends * closing block '}' of block operator (e.g. for, if,...). */ - this._offsets = [this._code.length]; + this._offsets = new Array(OConfig.codeMaxSize); /** * {Function} Class, which implement all supported operators */ @@ -88,41 +89,29 @@ class VM extends Observer { * @return {Number} Amount of run lines */ run(org) { - const code = this._code; - const lines = code.length; + const code = this._code; + const lines = code.length; if (lines < 1) {return 0} - const ops = this._ops; - const offs = this._offsets; - const period = OConfig.codeYieldPeriod; - const OFFS = Num.VAR_BITS_OFFS; - const WEIGHTS = this._weights; - let len = period; - let line = this._line; - let operator; + const ops = this._ops; + const operators = this._operators; + const period = OConfig.codeYieldPeriod; + const OP_OFFS = Num.VAR_BITS_OFFS; + const WEIGHTS = this._weights; + const LENS = Operators.LENS; + let len = period; + let line = this._line; while (len > 0 && org.energy > 0) { - operator = code[line] >>> OFFS; - line = ops[operator](code[line], line, org, lines); + const num = code[line]; + line = ops[num >>> LENS[num >>> OP_OFFS]].call(operators, line, num, org, lines); // - // This is very important peace of logic. As big the organism is - // as more energy he spends + // Every operator has it's own weight // - org.energy -= WEIGHTS[operator]; - // - // We found closing bracket '}' of some loop and have to return - // to the beginning of operator (e.g.: for) - // - while (offs.length > 1 && line === offs[offs.length - 1]) { - offs.pop(); - line = offs.pop(); - } + org.energy -= WEIGHTS[num >>> OP_OFFS]; // // We reach the end of the script and have to run it from the beginning // - if (line >= lines && org.energy > 0) { - line = 0; - this._operators.offsets = this._offsets = [code.length]; - } + line >= lines && org.energy > 0 && (line = 0); len--; } this._line = line; @@ -262,7 +251,7 @@ class VM extends Observer { _reset() { this.fire(EVENTS.RESET_CODE); this._line = 0; - this._operators.offsets = (this._offsets = [this._code.length]); + this._operators.updateIndexes(this._code); } /** diff --git a/common/src/FastArray.js b/common/src/FastArray.js index 24b5122..69cc68b 100644 --- a/common/src/FastArray.js +++ b/common/src/FastArray.js @@ -3,8 +3,7 @@ * 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! + * due performance issue. Removing element means setting null to specified index. * * @author flatline */ @@ -32,14 +31,14 @@ class FastArray { for (let i = 0; i < size; i++) { this._freeIndexes[i] = i; - this._arr[i] = 0; + this._arr[i] = null; } } destroy() { this._arr = null; this._freeIndexes = null; - this._size = 0; + this._size = null; } /** @@ -68,12 +67,12 @@ class FastArray { * optimization reason. Only a value * @param {*} v Any value except number */ - set(v) {this._arr[this._freeIndexes[this._index--]] = v} + add(v) {this._index > -1 && (this._arr[this._freeIndexes[this._index--]] = v)} /** * Returns a value by index * @param {Number} i Value index - * @returns {*} + * @returns {null|undefined|*} null - if cell is empty, undefined - if index out of bounds, * - value */ get(i) {return this._arr[i]} @@ -82,16 +81,17 @@ class FastArray { * @param {Number} i Value index */ del(i) { - if (this._arr !== 0) - this._arr[i] = 0; - this._freeIndexes[++this._index] = i; + if (this._arr[i] !== null) { + this._arr[i] = null; + this._freeIndexes[++this._index] = i; + } } /** * Returns last added value by set() method * @returns {*} Value */ - lastAdded() { + last() { return this._arr[this._freeIndexes[this._index + 1]]; } @@ -106,7 +106,7 @@ class FastArray { this._index = -1; arr.length = indexes.length = (this._size = size); for (let i = 0; i < size; i++) { - (arr[i] === 0) && (indexes[++this._index] = i); + (arr[i] === null) && (indexes[++this._index] = i); } } } From b4eb75d639a513885c6aefb121e0b2fae21eb1a9 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 5 Apr 2018 19:55:58 +0300 Subject: [PATCH 02/88] fixed wrong merge... --- client/src/manager/Manager.js | 8 +- client/src/manager/ManagerSpec.js | 50 +++---- .../src/manager/plugins/organisms/Config.js | 4 +- .../manager/plugins/organisms/Organisms.js | 129 +++++++----------- .../manager/plugins/organisms/dos/Organism.js | 2 +- .../plugins/organisms/dos/Organisms.js | 2 +- client/src/manager/plugins/status/Status.js | 19 +-- client/src/vm/VM.js | 2 +- common/src/FastArray.js | 13 +- common/src/Observer.js | 3 +- 10 files changed, 104 insertions(+), 128 deletions(-) diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index 190f614..6db88bd 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'); @@ -40,11 +40,11 @@ class Manager extends Observer { 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 + * {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 diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index 254c847..28c1ba5 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(man.positions.length).toBe(Config.worldWidth); 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'} @@ -765,8 +765,8 @@ 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() // man1.on(EVENTS.KILL, () => destroyFlag = true); // man1.on(EVENTS.STEP_IN, () => stepInBack = true); @@ -840,13 +840,13 @@ describe("client/src/manager/Manager", () => { // // man1.on(EVENTS.LOOP, () => { // if (iterated1 > 0 && org1 === null) { -// org1 = man1.organisms.first.val; +// org1 = man1.organisms.lastAdded(); // org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() // man1.on(EVENTS.KILL, () => destroyFlag = true); // man1.on(EVENTS.STEP_IN, () => stepInBack = true); // } else if (destroyFlag && stepInBack) { // stepInBack = false; -// expect(man1.organisms.size).toBe(1); +// expect(man1.organisms.length).toBe(1); // destroy(); // } // if (iterated1 > 10000) {throw 'Error sending organism between Servers'} @@ -897,7 +897,7 @@ describe("client/src/manager/Manager", () => { // testQ(done, // [server, SEVENTS.RUN, () => server.run(), () => {man1.run(() => man2.run(() => man3.run(() => waitObj.done = true)))}], // [waitObj], -// [man1, EVENTS.LOOP, emp, () => man1.organisms.first.val.vm.code.push(0b00001011000000000000000000000000)], // onStepRight() +// [man1, EVENTS.LOOP, emp, () => man1.organisms.lastAdded().vm.code.push(0b00001011000000000000000000000000)], // onStepRight() // [man3, EVENTS.STEP_IN, emp, () => destroy()] // ); // }); diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 931954f..b815405 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -90,12 +90,12 @@ 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: 4000, + orgCrossoverPeriod: 40000, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 5000, + orgRandomOrgPeriod: 50000, /** * {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 diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 28e0631..48c6b5c 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -55,20 +55,24 @@ class Organisms extends Configurable { * @abstract */ 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.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); @@ -78,32 +82,23 @@ 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++) {if (orgs.get(i)) {orgs.get(i).destroy()}} Helper.unoverride(this.parent, 'onIteration', this._onIterationCb); Helper.unoverride(this.parent, 'onLoop', this._onLoopCb); this._mutator.destroy(); this._mutator = null; + this.world = null; + this.positions = null; + this.organisms = null; this._onIterationCb = null; this._onLoopCb = null; 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; - } - } - addOrgHandlers(org) { org.on(ORG_EVENTS.DESTROY, this._onDestroyOrg.bind(this)); org.on(ORG_EVENTS.KILL_NO_ENERGY, this._onKillNoEnergyOrg.bind(this)); @@ -134,35 +129,27 @@ 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); + const orgs = this.organisms; + let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, parent); - item.val = org; + orgs.set(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 item; + return org.item; } /** * Returns random organism of current population - * @return {Organism|null} + * @return {Organism|false} */ _randOrg() { - const offs = Helper.rand(RAND_RANGE) + 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; + const org = this.organisms.get(Helper.rand(this.organisms.size)); + if (org === null) {return false} + return org; } /** @@ -172,13 +159,13 @@ 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; + let org; - while (org = item && item.val) { + for (let i = 0, len = orgs.size; i < len; i++) { + if ((org = orgs.get(i)) === null) {continue} org.run(); this.onOrganism(org); - item = item.next; } this._updateTournament(counter); @@ -194,6 +181,9 @@ class Organisms extends Configurable { 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; @@ -206,22 +196,21 @@ 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 || (item = this.createOrg(x, y, org)) === false) {return false} - let child = item.val; + if (x === -1 || this.createOrg(x, y, org) === false) {return false} + let child = this.organisms.lastAdded(); this.onClone(org, child); if (org.energy < 1 || child.energy < 1) {return false} this.parent.fire(EVENTS.CLONE, org, child, isCrossover); - return item; + return true; } _crossover(org1, org2) { - const item = this._clone(org1, true); - if (item === false) {return false} - let child = item.val; + if (!this._clone(org1, true)) {return false} + let child = this.organisms.lastAdded(); if (child.energy > 0 && org2.energy > 0) { child.changes += (Math.abs(child.vm.crossover(org2.vm)) * Num.MAX_BITS); @@ -247,37 +236,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 array * @param {Number|String} index Index or id - * @return {Organism} Organism instance or null + * @return {Organism|null} 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.x][org.y] = 0; @@ -294,15 +266,15 @@ class Organisms extends Configurable { _onCloneOrg(org) { //const maxOrgs = OConfig.orgMaxOrgs; - //const orgAmount = this.organisms.size; + //const orgAmount = this.organisms.length; //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 (this.organisms.size >= OConfig.orgMaxOrgs && Math.random() <= ((org.energy / 10000000000000) * (org.iterations / OConfig.orgAlivePeriod))) { + // if (this.organisms.length >= OConfig.orgMaxOrgs && Math.random() <= ((org.energy / 10000000000000) * (org.iterations / OConfig.orgAlivePeriod))) { // 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.length < maxOrgs) {this._clone(org)} + //if (this.organisms.length >= 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 @@ -311,17 +283,17 @@ 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) { + if (OConfig.orgKillOnClone && this.organisms.length >= 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)} + 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} + 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} @@ -340,12 +312,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} + 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); @@ -355,7 +328,7 @@ 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 @@ -378,7 +351,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 659788d..e6091ff 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -226,7 +226,7 @@ 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)) { + if (ret.ret = this.world.isFree(x, y) && this.organisms.length < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent)) { const item = this.createOrg(x, y); if (item === false) {return} const org = item.val; diff --git a/client/src/manager/plugins/status/Status.js b/client/src/manager/plugins/status/Status.js index 0ed60b6..983ad4d 100644 --- a/client/src/manager/plugins/status/Status.js +++ b/client/src/manager/plugins/status/Status.js @@ -133,29 +133,30 @@ class Status extends Configurable { } _onBeforeLoop(orgs) { - const size = orgs.size || 1; + const len = 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 size = orgs.size; let org; - while(item && (org = item.val)) { + for (let i = 0; i < size; i++) { + if ((org = orgs.get(i)) === null) {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; - this._changes = changes / size; - this._fitness = fitness / size; + this._energy = energy / len; + this._changes = changes / len; + this._fitness = fitness / len; this._codeSize = codeSize; } @@ -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..adaca47 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() || [248239118,260479783,290420886,180023848,29570522,354779824,220958594,315264606,231705066,47430264,290627113,366052124,159023662,55933308,219407615,41245567,259537331,120719242,284333530,113456602,354779824,35757647,276608152,211558321,285599842,264825877,76874876,263341538,292918152,78259025,143343650,22767412,330225150,284643353,231705066,47430264,290627113,366052124,142246446,55933308,219407615,41245567,259537331,120719242,284333530,113456602,354779824,35757647,315264606,276608152,211558321,285599842,277256487,171806725,12565195,149897134,226925351,322983007,35522715,175339998,262541555,276608144,161226673,285599842,226924839,289247237,355581321,71025539,265895966]; 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 index 24b5122..80c8d50 100644 --- a/common/src/FastArray.js +++ b/common/src/FastArray.js @@ -3,7 +3,7 @@ * 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. + * due performance issue. Removing element means setting null to specified index. * This class should not be used for storing numbers! * * @author flatline @@ -32,7 +32,7 @@ class FastArray { for (let i = 0; i < size; i++) { this._freeIndexes[i] = i; - this._arr[i] = 0; + this._arr[i] = null; } } @@ -82,9 +82,10 @@ class FastArray { * @param {Number} i Value index */ del(i) { - if (this._arr !== 0) - this._arr[i] = 0; - this._freeIndexes[++this._index] = i; + if (this._arr !== null) { + this._arr[i] = null; + this._freeIndexes[++this._index] = i; + } } /** @@ -106,7 +107,7 @@ class FastArray { this._index = -1; arr.length = indexes.length = (this._size = size); for (let i = 0; i < size; i++) { - (arr[i] === 0) && (indexes[++this._index] = i); + (arr[i] === null) && (indexes[++this._index] = i); } } } diff --git a/common/src/Observer.js b/common/src/Observer.js index 6e525a0..97e879c 100644 --- a/common/src/Observer.js +++ b/common/src/Observer.js @@ -53,8 +53,9 @@ 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. Not string + * @param {Number} event Event number * @param {*} args List of arguments + * @param args */ fire(event, ...args) { const handlers = this._handlers[event] || {}; From cce3cf1cf0871452875b90a25a9cbbc01f55028e Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 5 Apr 2018 22:55:51 +0300 Subject: [PATCH 03/88] fixed small syntax issues --- client/src/manager/ManagerSpec.js | 20 +++++++++---------- .../manager/plugins/organisms/Organisms.js | 12 ++++------- client/src/vm/VM.js | 2 +- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index 28c1ba5..37f9554 100644 --- a/client/src/manager/ManagerSpec.js +++ b/client/src/manager/ManagerSpec.js @@ -399,7 +399,7 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { - org1 = man1.organisms.lastAdded(); + org1 = man1.organisms.last(); org1.vm.insertLine(); org1.vm.updateLine(0, 0b00001011000000000000000000000000); // onStepRight() } else if (man2.organisms.length === 2) { @@ -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.lastAdded(); + org1 = man1.organisms.last(); org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() man1.on(EVENTS.STEP_OUT, () => { expect(doneInc < 3).toBe(true); @@ -475,13 +475,13 @@ describe("client/src/manager/Manager", () => { man2.on(EVENTS.STEP_IN, () => { ++doneInc; expect(man1.organisms.length).toBe(1); - expect(man1.organisms.lastAdded().x).toBe(0); + expect(man1.organisms.last().x).toBe(0); }); } else if (org1 !== null && org2 !== null && doneInc === 2) { expect(man1.organisms.length).toBe(1); - expect(man1.organisms.lastAdded().x).toBe(0); + expect(man1.organisms.last().x).toBe(0); expect(man2.organisms.length).toBe(1); - expect(man2.organisms.lastAdded().x).toBe(0); + expect(man2.organisms.last().x).toBe(0); destroy(); doneInc++; } @@ -489,7 +489,7 @@ describe("client/src/manager/Manager", () => { iterated1++; }); man2.on(EVENTS.LOOP, () => { - !iterated2 && (org2 = man2.organisms.lastAdded()); + !iterated2 && (org2 = man2.organisms.last()); iterated2++; }); @@ -555,7 +555,7 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { expect(man2.organisms.length).toBe(1); - org1 = man1.organisms.lastAdded(); + org1 = man1.organisms.last(); org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() } else if (man2.organisms.length === 2) { destroy(); @@ -766,7 +766,7 @@ describe("client/src/manager/Manager", () => { // man1.on(EVENTS.LOOP, () => { // if (iterated1 > 0 && iterated2 > 0 && org1 === null) { // expect(man2.organisms.length).toBe(1); -// org1 = man1.organisms.lastAdded(); +// org1 = man1.organisms.last(); // org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() // man1.on(EVENTS.KILL, () => destroyFlag = true); // man1.on(EVENTS.STEP_IN, () => stepInBack = true); @@ -840,7 +840,7 @@ describe("client/src/manager/Manager", () => { // // man1.on(EVENTS.LOOP, () => { // if (iterated1 > 0 && org1 === null) { -// org1 = man1.organisms.lastAdded(); +// org1 = man1.organisms.last(); // org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() // man1.on(EVENTS.KILL, () => destroyFlag = true); // man1.on(EVENTS.STEP_IN, () => stepInBack = true); @@ -897,7 +897,7 @@ describe("client/src/manager/Manager", () => { // testQ(done, // [server, SEVENTS.RUN, () => server.run(), () => {man1.run(() => man2.run(() => man3.run(() => waitObj.done = true)))}], // [waitObj], -// [man1, EVENTS.LOOP, emp, () => man1.organisms.lastAdded().vm.code.push(0b00001011000000000000000000000000)], // onStepRight() +// [man1, EVENTS.LOOP, emp, () => man1.organisms.last().vm.code.push(0b00001011000000000000000000000000)], // onStepRight() // [man3, EVENTS.STEP_IN, emp, () => destroy()] // ); // }); diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index f4cc15a..af8b78c 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -16,10 +16,6 @@ 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 { @@ -132,7 +128,7 @@ class Organisms extends Configurable { const orgs = this.organisms; let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, parent); - orgs.set(org); + orgs.add(org); this.addOrgHandlers(org); this.world.setDot(x, y, org.color); this.positions[x][y] = org; @@ -165,7 +161,7 @@ class Organisms extends Configurable { for (let i = 0, len = orgs.size; i < len; i++) { if ((org = orgs.get(i)) === null) {continue} org.run(); - //this.onOrganism(org); + this.onOrganism(org); } this._updateTournament(counter); @@ -199,7 +195,7 @@ class Organisms extends Configurable { [x, y] = this.world.getNearFreePos(org.x, org.y); if (x === -1 || this.createOrg(x, y, org) === false) {return false} - let child = this.organisms.lastAdded(); + let child = this.organisms.last(); this.onClone(org, child); if (org.energy < 1 || child.energy < 1) {return false} @@ -210,7 +206,7 @@ class Organisms extends Configurable { _crossover(org1, org2) { if (!this._clone(org1, true)) {return false} - let child = this.organisms.lastAdded(); + let child = this.organisms.last(); if (child.energy > 0 && org2.energy > 0) { child.changes += (Math.abs(child.vm.crossover(org2.vm)) * Num.MAX_BITS); diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index 3bbdd29..cedbcdf 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -111,7 +111,7 @@ class VM extends Observer { // // We reach the end of the script and have to run it from the beginning // - line >= lines && org.energy > 0 && (line = 0); + line >= lines && (line = 0); len--; } this._line = line; From c33c0f51acd0b79ec8e58e5aa13dee833a0955e7 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 6 Apr 2018 23:10:01 +0300 Subject: [PATCH 04/88] in progress with new DOS operators and VM #135, #117, #67 --- .../src/manager/plugins/organisms/Config.js | 2 +- .../src/manager/plugins/organisms/Mutator.js | 6 +- .../plugins/organisms/dos/Operators.js | 15 ++- client/src/vm/Num.js | 37 ++++---- client/src/vm/Operators.js | 91 ++++++++++--------- client/src/vm/VM.js | 38 ++++---- 6 files changed, 103 insertions(+), 86 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 2137632..1fd1d3a 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -162,7 +162,7 @@ const Config = { * {Number} Amount of bits for storing operator. This is first XX bits * in a number. */ - codeBitsPerOperator: 5, + codeBitsPerOperator: 6, /** * {Number} Amount of bits, which stores maximum block length. Under block * length we mean maximum amount of lines in one block like if, for,... diff --git a/client/src/manager/plugins/organisms/Mutator.js b/client/src/manager/plugins/organisms/Mutator.js index e7152a5..e8177c0 100644 --- a/client/src/manager/plugins/organisms/Mutator.js +++ b/client/src/manager/plugins/organisms/Mutator.js @@ -39,20 +39,20 @@ class Mutator { */ static _onSmallChange(org) { const rand = Helper.rand; - const vm = org.vm; + const vm = org.vm; const index = rand(vm.size); const rnd = rand(2); // // Toggles operator bits only // if (rnd === 0) { - vm.updateLine(index, Num.setOperator(vm.getLine(index), rand(vm.operators.operators.length))); + vm.updateLine(index, Num.setOperator(vm.getLine(index), rand(vm.operators.length))); org.changes += Num.BITS_PER_OPERATOR; // // Toggles specified bit, except operator bits // } else { - vm.updateLine(index, vm.getLine(index) ^ (1 << rand(Num.VAR_BITS_OFFS - 1))); + vm.updateLine(index, (vm.getLine(index) ^ (1 << rand(Num.VAR_BITS_OFFS - 1))) >>> 0); org.changes++; } } diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index a4e0cb5..5b0e065 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -21,12 +21,13 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; + this.OPERATOR_AMOUNT = 12; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point // IMPORTANT: to the Window // - Operators.compile(12); + Operators.compile(this.OPERATOR_AMOUNT); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); @@ -39,8 +40,8 @@ class OperatorsDos extends Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx xx 4 - * number: 01011 xxxxx 00 01 00 01... + * bits : 6 xx xx xx 4 + * number: 101011 00 01 00 01... * string: v0 = lookAt(v1, v0) */ static _compileLookAt() { @@ -60,7 +61,7 @@ class OperatorsDos extends Operators { vars[${v0}] = (IN_WORLD(x, y) ? (this._positions[x][y] <= 0 ? this._world.data[x][y] : this._positions[x][y].energy) : 0); return ++line; }`); - ops[h(`${'01011'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}`)] = this.global.fn; + ops[h(`${'101011'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}`)] = this.global.fn; } } } @@ -111,6 +112,12 @@ class OperatorsDos extends Operators { this._positions = man.positions; } + /** + * Returns operators array. Should be overridden in child class + * @abstract + */ + get length() {return OperatorsDos.OPERATOR_AMOUNT} + destroy() { super.destroy(); diff --git a/client/src/vm/Num.js b/client/src/vm/Num.js index 1a7c6a8..3c167b7 100644 --- a/client/src/vm/Num.js +++ b/client/src/vm/Num.js @@ -14,38 +14,41 @@ class Num { * script implementation */ static init(operatorAmount) { - this.MAX_BITS = 32; - this.OPERATOR_AMOUNT = operatorAmount; - this.BITS_PER_VAR = OConfig.codeBitsPerVar; - this.BITS_PER_OPERATOR = OConfig.codeBitsPerOperator; - this.NO_OPERATOR_MASK = 0xffffffff >>> this.BITS_PER_OPERATOR; - this.BITS_OF_TWO_VARS = this.BITS_PER_VAR * 2; - this.BITS_OF_FIRST_VAR = this.MAX_BITS - this.BITS_PER_VAR; - this.MAX_VAR = 1 << this.BITS_PER_VAR; - this.VAR_BITS_OFFS = this.MAX_BITS - this.BITS_PER_OPERATOR; + this.MAX_BITS = 32; + this.OPERATOR_AMOUNT = operatorAmount; + this.BITS_PER_VAR = OConfig.codeBitsPerVar; + this.BITS_PER_OPERATOR = OConfig.codeBitsPerOperator; + this.NO_OPERATOR_MASK = 0xffffffff >>> this.BITS_PER_OPERATOR; + this.OPERATOR_MASK_ON = 0x80000000; + this.OPERATOR_MASK_OFF = 0x7fffffff; + this.BITS_OF_TWO_VARS = this.BITS_PER_VAR * 2; + this.BITS_OF_FIRST_VAR = this.MAX_BITS - this.BITS_PER_VAR; + this.MAX_VAR = 1 << this.BITS_PER_VAR; + this.VAR_BITS_OFFS = this.MAX_BITS - this.BITS_PER_OPERATOR; - this.BITS_OF_VAR0 = this.BITS_PER_OPERATOR; - this.BITS_OF_VAR1 = this.BITS_PER_OPERATOR + this.BITS_PER_VAR; - this.BITS_OF_VAR2 = this.BITS_PER_OPERATOR + 2 * this.BITS_PER_VAR; - this.BITS_OF_VAR3 = this.BITS_PER_OPERATOR + 3 * this.BITS_PER_VAR; + this.BITS_OF_VAR0 = this.BITS_PER_OPERATOR; + this.BITS_OF_VAR1 = this.BITS_PER_OPERATOR + this.BITS_PER_VAR; + this.BITS_OF_VAR2 = this.BITS_PER_OPERATOR + 2 * this.BITS_PER_VAR; + this.BITS_OF_VAR3 = this.BITS_PER_OPERATOR + 3 * this.BITS_PER_VAR; } /** * Returns random number for byte code. We have to use >>> 0 at * the end, because << operator works with signed 32bit numbers, - * but not with unsigned like we need + * but not with unsigned like we need. We have to use mask - zero + * bit turned on to prevent duplication of operators+data values. * @returns {number} */ static rand() { - return (Helper.rand(this.OPERATOR_AMOUNT) << (this.VAR_BITS_OFFS) | Helper.rand(this.NO_OPERATOR_MASK)) >>> 0; + return ((Helper.rand(this.OPERATOR_AMOUNT) << (this.VAR_BITS_OFFS) | Helper.rand(this.NO_OPERATOR_MASK)) | this.OPERATOR_MASK_ON) >>> 0; } static getOperator(num) { - return num >>> this.VAR_BITS_OFFS; + return (num & this.OPERATOR_MASK_OFF) >>> this.VAR_BITS_OFFS; } static setOperator(num, op) { - return (op << this.VAR_BITS_OFFS | (num & this.NO_OPERATOR_MASK)) >>> 0; + return ((op << this.VAR_BITS_OFFS | (num & this.NO_OPERATOR_MASK)) | this.OPERATOR_MASK_ON) >>> 0; } static getVar(num, index = 0) { diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 12e4a62..53d11d2 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -7,12 +7,14 @@ const OConfig = require('./../manager/plugins/organisms/Config'); const Num = require('./Num'); +const OPERATOR_AMOUNT = 11; + class Operators { /** * Compiles all variants of bite-code to speed up the execution. * @param {Number} operators Amount of operators */ - static compile(operators = 11) { + static compile(operators = OPERATOR_AMOUNT) { const bitsPerOp = OConfig.codeBitsPerOperator; const MAX_BITS = 32; /** @@ -118,8 +120,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx - * number: 00000 xxxxx 00 01... + * bits : 6 xx xx + * number: 100000 00 01... * string: v0 = v1 */ static _compileVar() { @@ -135,7 +137,7 @@ class Operators { this.vars[${v0}] = this.vars[${v1}]; return ++line; }`); - ops[h(`${'00000'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + ops[h(`${'100000'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; } } } @@ -146,8 +148,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx - * number: 000001 xxxxx 00 01... + * bits : 6 xx xx + * number: 100001 00 01... * string: v0 = 1 */ static _compileConst() { @@ -164,7 +166,7 @@ class Operators { this.vars[${v0}] = num << ${bits1var} >>> ${bits}; return ++line; }`); - ops[h(`${'00001'}${b(v0, bpv)}`)] = this.global.fn; + ops[h(`${'100001'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -174,8 +176,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx 2 - * number: 00010 xxxxx 00 01 00... + * bits : 6 xx xx 2 + * number: 100010 00 01 00... * string: if (v0 < v1) { */ static _compileIf() { @@ -190,9 +192,9 @@ class Operators { for (let v1 = 0; v1 < vars; v1++) { eval(`Operators.global.fn = function (line) { if (this.vars[${v0}] ${this._CONDITIONS[c]} this.vars[${v1}]) {return ++line} - return this.offs[line]; + return this.offs[line] === line ? ++line : this.offs[line]; }`); - ops[h(`${'00010'}${b(v0, bpv)}${b(v1, bpv)}${b(c, this.CONDITION_BITS)}`)] = this.global.fn; + ops[h(`${'100010'}${b(v0, bpv)}${b(v1, bpv)}${b(c, this.CONDITION_BITS)}`)] = this.global.fn; } } } @@ -204,8 +206,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx 2 - * number: 00011 xxxxx 00 01 00... + * bits : 6 xx xx 2 + * number: 100011 00 01 00... * string: while (v0 < v1) { */ static _compileLoop() { @@ -220,9 +222,9 @@ class Operators { for (let v1 = 0; v1 < vars; v1++) { eval(`Operators.global.fn = function (line) { if (this.vars[${v0}] ${this._CONDITIONS[c]} this.vars[${v1}]) {return ++line} - return this.offs[line]; + return this.offs[line] === line ? ++line : this.offs[line]; }`); - ops[h(`${'00011'}${b(v0, bpv)}${b(v1, bpv)}${b(c, this.CONDITION_BITS)}`)] = this.global.fn; + ops[h(`${'100011'}${b(v0, bpv)}${b(v1, bpv)}${b(c, this.CONDITION_BITS)}`)] = this.global.fn; } } } @@ -234,8 +236,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx xx 4 - * number: 00100 xxxxx 00 01 00 01... + * bits : 6 xx xx xx 4 + * number: 100100 00 01 00 01... * string: v0 = v1 - v0 */ static _compileOperator() { @@ -253,7 +255,7 @@ class Operators { ${this._OPERATORS[op](v0, v1, v2)} return ++line; }`); - ops[h(`${'00100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}${b(op, this.FOUR_BITS)}`)] = this.global.fn; + ops[h(`${'100100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}${b(op, this.FOUR_BITS)}`)] = this.global.fn; } } } @@ -266,16 +268,16 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Function name consists of 10 bits. Example: * - * bits : 5 5 10 - * number: 00101 xxxxx 0000000001... + * bits : 6 10 + * number: 100101 0000000001... * string: func n */ static _compileFunc() { const ops = this._compiledOperators; const h = this._toHexNum; - eval(`Operators.global.fn = function (line) {return this.offs[line]}`); - ops[h(`${'00101'}`)] = this.global.fn; + eval(`Operators.global.fn = function (line) {return this.offs[line] === line ? ++line : this.offs[line]}`); + ops[h(`${'100101'}`)] = this.global.fn; } /** @@ -284,8 +286,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Function name consists of 10 bits. Example: * - * bits : 5 5 10 - * number: 00110 xxxxx 0000000001... + * bits : 6 10 + * number: 100110 0000000001... * string: call n */ static _compileFuncCall() { @@ -303,7 +305,7 @@ class Operators { } return ++line; }`); - ops[h(`${'00110'}`)] = this.global.fn; + ops[h(`${'100110'}`)] = this.global.fn; } /** @@ -312,8 +314,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 - * number: 00111 xxxxx... + * bits : 6 + * number: 100111 ... * string: return */ static _compileReturn() { @@ -330,7 +332,7 @@ class Operators { } return 0; }`); - ops[h(`${'00111'}`)] = this.global.fn; + ops[h(`${'100111'}`)] = this.global.fn; } /** @@ -339,8 +341,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 - * number: 01000 xxxxx... + * bits : 6 + * number: 101000... * string: } */ static _compileBracket() { @@ -359,7 +361,7 @@ class Operators { } return ++line; }`); - ops[h(`${'01000'}`)] = this.global.fn; + ops[h(`${'101000'}`)] = this.global.fn; } /** @@ -368,8 +370,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx - * number: 01001 xxxxx 00 01... + * bits : 6 xx xx + * number: 101001 00 01... * string: toMem(v0, v1) */ static _compileToMem() { @@ -378,16 +380,16 @@ class Operators { const h = this._toHexNum; const b = this._toBinStr; const vars = Math.pow(2, bpv); - const memLen = Math.pow(2, OConfig.orgMemBits); + const memLen = Math.pow(2, OConfig.orgMemBits) - 1; for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { eval(`Operators.global.fn = function (line, num, org) { const offs = ((this.vars[${v0}] + .5) << 0) >>> 0; - org.mem[offs >= ${memLen} ? ${memLen-1} : offs] = this.vars[${v1}]; + org.mem[offs > ${memLen} ? ${memLen} : offs] = this.vars[${v1}]; return ++line; }`); - ops[h(`${'01001'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + ops[h(`${'101001'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; } } } @@ -398,8 +400,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 5 5 xx xx - * number: 01010 xxxxx 00 01... + * bits : 6 xx xx + * number: 101010 00 01... * string: v0 = fromMem(v1) */ static _compileFromMem() { @@ -417,7 +419,7 @@ class Operators { this.vars[${v0}] = org.mem[offs >= ${memLen} ? ${memLen-1} : offs]; return ++line; }`); - ops[h(`${'01010'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + ops[h(`${'101010'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; } } } @@ -436,7 +438,6 @@ class Operators { * {Object} Handlers map, which handle every variant of byte-code */ this._OPERATORS_CB = Operators._compiledOperators; - this.lens = Operators.LENS; this.stack = []; this.funcs = []; } @@ -448,19 +449,21 @@ class Operators { updateIndexes(code) { const len = code.length; const varOffs = Num.VAR_BITS_OFFS; + const opMask = Num.OPERATOR_MASK_OFF; const offs = this.offs; const funcs = this.funcs = []; const blocks = []; + this.stack = []; for (let i = 0; i < len; i++) { - const operator = code[i] >>> varOffs; + const operator = (code[i] & opMask) >>> varOffs; if (operator === 0x2 || operator === 0x3) { // if, while - offs[i] = i + 1; + offs[i] = i; blocks.push(i); continue; } if (operator === 0x5) { // func - offs[i] = i + 1; + offs[i] = i; funcs.push(i + 1); blocks.push(i); continue; @@ -486,6 +489,8 @@ class Operators { * Returns operators array. Should be overridden in child class * @abstract */ + get length() {return OPERATOR_AMOUNT} + get operators() {return this._OPERATORS_CB} /** diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index cedbcdf..bf37adc 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -46,7 +46,7 @@ class VM extends Observer { * to return if first line appears. second - line number, where ends * closing block '}' of block operator (e.g. for, if,...). */ - this._offsets = new Array(OConfig.codeMaxSize); + this._offsets = parent ? parent.offsets.slice() : new Array(OConfig.codeMaxSize); /** * {Function} Class, which implement all supported operators */ @@ -57,6 +57,7 @@ class VM extends Observer { get code() {return this._code} get size() {return this._code.length} get operators() {return this._operators} + get offsets() {return this._offsets} get vars() {return this._vars} get line() {return this._line} @@ -89,34 +90,35 @@ class VM extends Observer { * @return {Number} Amount of run lines */ run(org) { - const code = this._code; - const lines = code.length; - if (lines < 1) {return 0} - const ops = this._ops; - const operators = this._operators; - const period = OConfig.codeYieldPeriod; - const OP_OFFS = Num.VAR_BITS_OFFS; - const WEIGHTS = this._weights; - const LENS = Operators.LENS; - let len = period; - let line = this._line; + const code = this._code; + const codeLen = code.length; + if (codeLen < 1) {return 0} + const opHandlers = this._ops; + const operators = this._operators; + const yieldPeriod = OConfig.codeYieldPeriod; + const opOffs = Num.VAR_BITS_OFFS; + const opMask = Num.OPERATOR_MASK_OFF; + const weights = this._weights; + const lens = Operators.LENS; + let linesRun = yieldPeriod; + let line = this._line; - while (len > 0 && org.energy > 0) { + while (linesRun > 0 && org.energy > 0) { const num = code[line]; - line = ops[num >>> LENS[num >>> OP_OFFS]].call(operators, line, num, org, lines); + line = opHandlers[num >>> lens[(num & opMask) >>> opOffs]].call(operators, line, num, org, code); // // Every operator has it's own weight // - org.energy -= WEIGHTS[num >>> OP_OFFS]; + org.energy -= weights[(num & opMask) >>> opOffs]; // // We reach the end of the script and have to run it from the beginning // - line >= lines && (line = 0); - len--; + line >= codeLen && (line = 0); + linesRun--; } this._line = line; - return period - len; + return yieldPeriod - linesRun; } destroy() { From c7ad66651ffe40e39cf31a754b87539270ef9d94 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 7 Apr 2018 20:05:21 +0300 Subject: [PATCH 05/88] in progress with new DOS operators and VM #135, #117, #67 --- .../plugins/organisms/dos/Operators.js | 2 +- client/src/vm/Operators.js | 70 +++++++++++-------- client/src/vm/VM.js | 5 +- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 5b0e065..9f1e3b5 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -31,7 +31,7 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); - this._compileLookAt(); + this._compileLookAt(); // 11 } /** diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 53d11d2..37c5180 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -81,17 +81,17 @@ class Operators { // arguments. This is how we dramatically speed up byte-code interpretation // Num.init(operators); - this._compileVar(); - this._compileConst(); - this._compileIf(); - this._compileLoop(); - this._compileOperator(); - this._compileFunc(); - this._compileFuncCall(); - this._compileReturn(); - this._compileBracket(); - this._compileToMem(); - this._compileFromMem(); + this._compileVar(); // 0 + this._compileConst(); // 1 + this._compileIf(); // 2 + this._compileLoop(); // 3 + this._compileOperator(); // 4 + this._compileFunc(); // 5 + this._compileFuncCall(); // 6 + this._compileReturn(); // 7 + this._compileBracket(); // 8 + this._compileToMem(); // 9 + this._compileFromMem(); // 10 } /** @@ -284,23 +284,27 @@ class Operators { * Compiles all variants of function call operator and stores they in * this._compiledOperators map. 'xx' means, that amount of bits * depends on configuration. '...' means, that all other bits are - * ignored. Function name consists of 10 bits. Example: + * ignored. If condition bit is set to 0, then variable value will be + * used as function name. If 1 then hard coded functions name will be + * get from byte-code. Function name consists of 10 bits. Example: * - * bits : 6 10 - * number: 100110 0000000001... - * string: call n + * bits : 6 1 10 + * number: 100110 0 0000000001... + * string: call v1 */ static _compileFuncCall() { - const ops = this._compiledOperators; - const h = this._toHexNum; - const bits = Num.MAX_BITS - this.FUNC_NAME_BITS; - const opBits = Num.BITS_PER_OPERATOR; + const ops = this._compiledOperators; + const h = this._toHexNum; + const ifBit = Num.MAX_BITS - 1; + const fnBits = Num.MAX_BITS - this.FUNC_NAME_BITS; + const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar; + const opBits = Num.BITS_PER_OPERATOR; eval(`Operators.global.fn = function (line, num) { - const offs = this.funcs[num << ${opBits} >>> ${bits}]; + const data = num << ${opBits}; + const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? this.vars[(data >>> ${varBits} * .5 + .5) << 0] : data >>> ${fnBits}]; if (typeof offs !== 'undefined') { - this.stack.push(line + 1); - this.stack.push(this.vars.slice()); + this.stack.push(line + 1, offs - 1, this.vars.slice()); return offs; } return ++line; @@ -328,6 +332,7 @@ class Operators { const stackVars = this.stack.pop(); const vars = this.vars; for (let i = 0; i < ${vars}; i++) {vars[i] = stackVars[i]} + stack.pop(); return this.stack.pop(); } return 0; @@ -349,15 +354,21 @@ class Operators { const ops = this._compiledOperators; const h = this._toHexNum; const vars = Math.pow(2, OConfig.codeBitsPerVar); + const opMask = Num.OPERATOR_MASK_OFF; eval(`Operators.global.fn = function (line, num, org, lines) { - const operator = lines[this.offs[line]] >>> Num.VAR_BITS_OFFS; + const startLine = this.offs[line]; + const operator = (lines[startLine] & ${opMask}) >>> Num.VAR_BITS_OFFS; if (operator === 0x3) {return this.offs[line]} // loop if (operator === 0x5) { // func - const stackVars = this.stack.pop(); - const vars = this.vars; - for (let i = 0; i < ${vars}; i++) {vars[i] = stackVars[i]} - return this.stack.pop(); + const stack = this.stack; + if (stack[stack.length - 2] === startLine) { + const stackVars = stack.pop(); + const vars = this.vars; + for (let i = 0; i < ${vars}; i++) {vars[i] = stackVars[i]} + stack.pop(); + return this.stack.pop(); + } } return ++line; }`); @@ -425,6 +436,7 @@ class Operators { } constructor(offs, vars) { + this._MAX_FUNC_AMOUNT = Math.pow(2, Operators.FUNC_NAME_BITS); /** * {Array} Array of offsets for closing braces. For 'for', 'if' * and other operators. @@ -439,7 +451,7 @@ class Operators { */ this._OPERATORS_CB = Operators._compiledOperators; this.stack = []; - this.funcs = []; + this.funcs = new Array(this._MAX_FUNC_AMOUNT); } /** @@ -451,7 +463,7 @@ class Operators { const varOffs = Num.VAR_BITS_OFFS; const opMask = Num.OPERATOR_MASK_OFF; const offs = this.offs; - const funcs = this.funcs = []; + const funcs = this.funcs = new Array(this._MAX_FUNC_AMOUNT); const blocks = []; this.stack = []; diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index bf37adc..b629add 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -105,11 +105,12 @@ class VM extends Observer { while (linesRun > 0 && org.energy > 0) { const num = code[line]; - line = opHandlers[num >>> lens[(num & opMask) >>> opOffs]].call(operators, line, num, org, code); + const op = (num & opMask) >>> opOffs; + line = opHandlers[num >>> lens[op]].call(operators, line, num, org, code); // // Every operator has it's own weight // - org.energy -= weights[(num & opMask) >>> opOffs]; + org.energy -= weights[op]; // // We reach the end of the script and have to run it from the beginning // From 0d5e350151d6b16c6a741537e8cfa4364b4cc2b9 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 7 Apr 2018 23:18:10 +0300 Subject: [PATCH 06/88] in progress with new DOS operators and VM #135, #117, #67 added new operators --- .../src/manager/plugins/organisms/Organism.js | 7 +- .../plugins/organisms/dos/Operators.js | 109 +++++++++++++++++- .../plugins/organisms/dos/OrganismSpec.js | 9 -- client/src/vm/Operators.js | 2 +- common/src/Directions.js | 29 ++++- 5 files changed, 140 insertions(+), 16 deletions(-) diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index c1a7ff2..77c9ed5 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -11,6 +11,8 @@ const Helper = require('./../../../../../common/src/Helper'); const OConfig = require('./../../../manager/plugins/organisms/Config'); const EVENT_AMOUNT = require('./../../../share/Events').EVENT_AMOUNT; const VM = require('./../../../vm/VM'); +const DIR = require('./../../../../../common/src/Directions').DIR; +const OFFSX = require('./../../../../../common/src/Directions').OFFSX; const DESTROY = 0; const CLONE = 1; @@ -93,6 +95,7 @@ class Organism extends Observer { get id() {return this._id} get x() {return this._x} get y() {return this._y} + get dir() {return this._dir} get item() {return this._item} get iterations() {return this._iterations} get changes() {return this._changes} @@ -103,7 +106,6 @@ class Organism extends Observer { get startEnergy() {return this._startEnergy} get color() {return this._color} get mem() {return this._mem} - get posId() {return Helper.posId(this._x, this._y)} set x(newX) {this._x = newX} set y(newY) {this._y = newY} @@ -112,6 +114,7 @@ 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 dir(d) {this._dir = d} /** * Runs one code iteration (amount of lines set in Config.codeYieldPeriod) and returns @@ -220,6 +223,7 @@ class Organism extends Observer { this._mutationPeriod = OConfig.orgRainMutationPeriod; this._mutationPercent = OConfig.orgRainMutationPercent; this._mem = new Array(Math.pow(2, OConfig.orgMemBits)); + this._dir = Helper.rand(OFFSX.length); _fill(this._mem, 0); } @@ -233,6 +237,7 @@ class Organism extends Observer { this._mutationPeriod = parent.mutationPeriod; this._mutationPercent = parent.mutationPercent; this._mem = parent.mem.slice(); + this._dir = parent.dir; } _updateColor() { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 9f1e3b5..964c4ad 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -11,6 +11,8 @@ const EVENTS = require('./../../../../../src/share/Events').EVENTS; const OConfig = require('./../Config'); const Operators = require('./../../../../vm/Operators'); const Num = require('./../../../../vm/Num'); +const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; +const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; /** * {Function} Is created to speed up this function call. constants are run @@ -21,7 +23,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; - this.OPERATOR_AMOUNT = 12; + this.OPERATOR_AMOUNT = 16; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -30,8 +32,16 @@ class OperatorsDos extends Operators { Operators.compile(this.OPERATOR_AMOUNT); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); + this.LENS.push(Num.MAX_BITS - bitsPerOp); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this._compileLookAt(); // 11 + this._compileStep(); // 12 + this._compileDir(); // 13 + this._compileMyX(); // 14 + this._compileMyY(); // 15 } /** @@ -67,6 +77,103 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'step' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 + * number: 101100... + * string: step + */ + static _compileStep() { + eval(`OperatorsDos.global.fn = function (line, num, org) { + this._obs.fire(${EVENTS.STEP}, org, org.x, org.y, org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); + return ++line; + }`); + this._compiledOperators[this._toHexNum(`${'101100'}`)] = this.global.fn; + } + + /** + * Compiles all variants of 'dir' operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 6 xx + * number: 101101 11... + * string: dir(v3) + */ + static _compileDir() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + const dirs = OFFSX.length; + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function (line, num, org) { + org.dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; + return ++line; + }`); + ops[h(`${'101101'}${b(v0, bpv)}`)] = this.global.fn; + } + } + + /** + * Compiles all variants of 'myX' operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 6 xx + * number: 101110 00... + * string: v0 = myX() + */ + static _compileMyX() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function (line, num, org) { + this.vars[${v0}] = org.x; + return ++line; + }`); + ops[h(`${'101110'}${b(v0, bpv)}`)] = this.global.fn; + } + } + + /** + * Compiles all variants of 'myY' operator and stores they in + * this._compiledOperators map. 'xx' means, that amount of bits + * depends on configuration. '...' means, that all other bits are + * ignored. Example: + * + * bits : 6 xx + * number: 101111 00... + * string: v0 = myY() + */ + static _compileMyY() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function (line, num, org) { + this.vars[${v0}] = org.y; + return ++line; + }`); + ops[h(`${'101111'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** diff --git a/client/src/manager/plugins/organisms/dos/OrganismSpec.js b/client/src/manager/plugins/organisms/dos/OrganismSpec.js index 460d1b0..f31bcbb 100644 --- a/client/src/manager/plugins/organisms/dos/OrganismSpec.js +++ b/client/src/manager/plugins/organisms/dos/OrganismSpec.js @@ -165,15 +165,6 @@ describe("client/src/organism/OrganismDos", () => { }); describe('Checks coordinates', () => { - it('posId() should return unique hash', () => { - org.x = 2; - org.y = 3; - expect(org.posId).toBe(Helper.posId(2, 3)); - org.x = 0; - org.y = 3; - expect(org.posId).toBe(Helper.posId(0, 3)); - }); - it('Checks coordinates setters getters', () => { org.x = 1; org.y = 2; diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 37c5180..4077b41 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -302,7 +302,7 @@ class Operators { eval(`Operators.global.fn = function (line, num) { const data = num << ${opBits}; - const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? this.vars[(data >>> ${varBits} * .5 + .5) << 0] : data >>> ${fnBits}]; + const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? this.vars[(data >>> ${varBits} + .5) << 0] : data >>> ${fnBits}]; if (typeof offs !== 'undefined') { this.stack.push(line + 1, offs - 1, this.vars.slice()); return offs; diff --git a/common/src/Directions.js b/common/src/Directions.js index 07604e9..d752024 100644 --- a/common/src/Directions.js +++ b/common/src/Directions.js @@ -10,6 +10,16 @@ const DIR = { LEFT : 3, NO : 4 }; +/** + * {Array} Array of flipped directions. Is used for connecting with nearest + * servers: left -> right, up -> down, right -> left, down -> up + */ +const FLIP_DIR = [ + DIR.DOWN, + DIR.LEFT, + DIR.UP, + DIR.RIGHT +]; const NAMES = { 0: 'Up', @@ -19,9 +29,20 @@ const NAMES = { 4: 'No' }; /** - * {Array} Array of flipped directions. Is used for connecting with nearest - * servers: left -> right, up -> down, right -> left, down -> up + * {Array} X, Y Offsets values for directions. Are used to change current + * coordinates of some object (organism or world object) */ -const FLIP_DIR = [DIR.DOWN, DIR.LEFT, DIR.UP, DIR.RIGHT]; +const OFFSX = [ + 0, // Up + 1, // Right + 0, // Down + -1 // Left +]; +const OFFSY = [ + -1, // Up + 0, // Right + 1, // Down + 0 // Left +]; -module.exports = {DIR, FLIP_DIR, NAMES}; \ No newline at end of file +module.exports = {DIR, FLIP_DIR, NAMES, OFFSX, OFFSY}; \ No newline at end of file From 27c55f5521773f9cb4ed2827033c65f59e8d2af3 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 11 Apr 2018 23:48:31 +0300 Subject: [PATCH 07/88] in progress with new DOS operators and VM #135, #117, #67 refactored plugins: Energy, Stones, Objects added commands: eat, put, energy, pick updated color scheme refactored configs improved if operator --- client/src/manager/ManagerSpec.js | 6 +- client/src/manager/plugins/Energy.js | 89 -------- client/src/manager/plugins/Stones.js | 74 ------- client/src/manager/plugins/energy/Config.js | 36 +++ client/src/manager/plugins/energy/Energy.js | 100 +++++++++ client/src/manager/plugins/objects/Config.js | 30 +++ client/src/manager/plugins/objects/Objects.js | 86 ++++++++ .../src/manager/plugins/organisms/Config.js | 28 +-- .../src/manager/plugins/organisms/Organism.js | 19 +- .../plugins/organisms/dos/Operators.js | 207 ++++++++++++++++-- client/src/manager/plugins/stones/Config.js | 21 ++ client/src/manager/plugins/stones/Stones.js | 79 +++++++ client/src/share/Config.js | 42 +--- client/src/share/Dots.js | 120 ++++++++++ client/src/view/Canvas.js | 1 + client/src/vm/Operators.js | 39 ++-- 16 files changed, 717 insertions(+), 260 deletions(-) delete mode 100644 client/src/manager/plugins/Energy.js delete mode 100644 client/src/manager/plugins/Stones.js create mode 100644 client/src/manager/plugins/energy/Config.js create mode 100644 client/src/manager/plugins/energy/Energy.js create mode 100644 client/src/manager/plugins/objects/Config.js create mode 100644 client/src/manager/plugins/objects/Objects.js create mode 100644 client/src/manager/plugins/stones/Config.js create mode 100644 client/src/manager/plugins/stones/Stones.js create mode 100644 client/src/share/Dots.js diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index 37f9554..ee8fe93 100644 --- a/client/src/manager/ManagerSpec.js +++ b/client/src/manager/ManagerSpec.js @@ -19,7 +19,7 @@ describe("client/src/manager/Manager", () => { const port = SConfig.port; const maxConns = SConfig.maxConnections; const startOrgs = OConfig.orgStartAmount; - const energyCheck = Config.worldEnergyCheckPeriod; + const energyCheck = Config.checkPeriod; const emp = () => {}; let error; @@ -49,7 +49,7 @@ describe("client/src/manager/Manager", () => { SConfig.port = Config.serverPort; SConfig.maxConnections = 100; OConfig.orgStartAmount = 0; - Config.worldEnergyCheckPeriod = 0; + Config.checkPeriod = 0; error = Console.error; warn = Console.warn; @@ -80,7 +80,7 @@ describe("client/src/manager/Manager", () => { SConfig.port = port; SConfig.maxConnections = maxConns; OConfig.orgStartAmount = startOrgs; - Config.worldEnergyCheckPeriod = energyCheck; + Config.checkPeriod = energyCheck; }); describe('Manager creation/destroy', () => { diff --git a/client/src/manager/plugins/Energy.js b/client/src/manager/plugins/Energy.js deleted file mode 100644 index 938057a..0000000 --- a/client/src/manager/plugins/Energy.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * Manager's plugin, which tracks amount of energy in a world and updates it. - * - * @author flatline - */ -const Helper = require('./../../../../common/src/Helper'); -const Config = require('./../../share/Config').Config; -const Organism = require('./../../manager/plugins/organisms/Organism').Organism; -const EVENTS = require('./../../share/Events').EVENTS; - -class Energy { - constructor(manager) { - this._manager = manager; - this._onIterationCb = this._onIteration.bind(this); - - Helper.override(manager, 'onIteration', this._onIterationCb); - } - - destroy() { - Helper.unoverride(this._manager, 'onIteration', this._onIterationCb); - this._manager = null; - this._onIterationCb = null; - } - - _onIteration(counter) { - if (Config.worldEnergyCheckPeriod === 0 || counter % Config.worldEnergyCheckPeriod !== 0) {return} - - let energy = this._getEnergyPercent(); - - this._manager.fire(EVENTS.WORLD_ENERGY, energy); - if (energy > Config.worldEnergyMinPercent) {return} - - const maxEnergy = Config.worldEnergyMaxPercent * Config.worldWidth * Config.worldHeight; - 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 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 (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; - const height = Config.worldHeight; - - for (let x = 0; x < width; x++) { - for (let y = 0; y < height; y++) { - if (world.getDot(x, y) > 0) {++energy} - } - } - - return energy / (width * height); - } -} - -module.exports = Energy; \ No newline at end of file diff --git a/client/src/manager/plugins/Stones.js b/client/src/manager/plugins/Stones.js deleted file mode 100644 index 344b717..0000000 --- a/client/src/manager/plugins/Stones.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * 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; -// -// We have to add stone type to global types storage -// -OBJECT_TYPES.TYPE_STONE = -(Object.keys(OBJECT_TYPES).length + 1); - -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.worldStonesPercent === .0) {return} - - 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 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 amount} - if (world.isFree(x, y)) { - if (world.setDot(x, y, color)) { - man.positions[x][y] = stone; - if (++amount >= stones) {return amount} - } - } - } - - return amount; - } -} - -module.exports = Stones; \ No newline at end of file diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js new file mode 100644 index 0000000..6dbca2b --- /dev/null +++ b/client/src/manager/plugins/energy/Config.js @@ -0,0 +1,36 @@ +/** + * Configuration of Energy plugin + * + * @author flatline + */ +const Config = { + /** + * {Number} An amount of iteration, after which we have to check world energy + * percent. May be 0 if you want to disable energy generation + */ + checkPeriod: 5000, + /** + * {Number} size of one clever energy block in dots + */ + blockSize: 10, + /** + * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS + * constant for details + */ + colorIndex: 9174, + /** + * {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 + * be less then minPercent. These two configs create cyclical + * energy adding to the world. + */ + maxPercent: .3, + /** + * {Number} Opposite to maxPercent. Sets minimum percent from + * all energy in a world after which clever energy will turn on (be added to the + * world again). + */ + minPercent: .28 +}; + +module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/energy/Energy.js b/client/src/manager/plugins/energy/Energy.js new file mode 100644 index 0000000..5fb7f46 --- /dev/null +++ b/client/src/manager/plugins/energy/Energy.js @@ -0,0 +1,100 @@ +/** + * Manager's plugin, which tracks amount of energy in a world and updates it. + * + * @author flatline + */ +const Dots = require('./../../../share/Dots'); +const Config = require('./Config'); +const EVENTS = require('./../../../share/Events').EVENTS; + +class Energy extends Dots { + constructor(manager) { + super(manager, Config, { + addOnce : false, + checkPeriod: Config.checkPeriod, + minPercent : Config.minPercent, + maxPercent : Config.maxPercent, + colorIndex : Config.colorIndex, + blockSize : Config.blockSize, + compareCb : (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0 + }); + //this._manager = manager; + //this._onIterationCb = this._onIteration.bind(this); + + //Helper.override(manager, 'onIteration', this._onIterationCb); + } + + onIteration(counter) { + const energy = super.onIteration(counter); + energy !== false && this.manager.fire(EVENTS.WORLD_ENERGY, energy); + } + + // destroy() { + // Helper.unoverride(this._manager, 'onIteration', this._onIterationCb); + // this._manager = null; + // this._onIterationCb = null; + // } + // + // _onIteration(counter) { + // if (Config.worldEnergyCheckPeriod === 0 || counter % Config.worldEnergyCheckPeriod !== 0) {return} + // + // let energy = this._getEnergyPercent(); + // + // this._manager.fire(EVENTS.WORLD_ENERGY, energy); + // if (energy > Config.worldEnergyMinPercent) {return} + // + // const maxEnergy = Config.worldEnergyMaxPercent * Config.worldWidth * Config.worldHeight; + // 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 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 (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; + // const height = Config.worldHeight; + // + // for (let x = 0; x < width; x++) { + // for (let y = 0; y < height; y++) { + // if (world.getDot(x, y) > 0) {++energy} + // } + // } + // + // return energy / (width * height); + // } +} + +module.exports = Energy; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js new file mode 100644 index 0000000..2cf1531 --- /dev/null +++ b/client/src/manager/plugins/objects/Config.js @@ -0,0 +1,30 @@ +/** + * Configuration of Objects plugin + * + * @author flatline + */ +const Config = { + /** + * {Number} An amount of iteration, after which we have to check world energy + * objects percent. May be 0 if you want to disable energy objects generation + */ + checkPeriod: 6000, + /** + * {Number} size of one energy objects block in dots + */ + blockSize: 10, + /** + * {Number} Percent from all energy objects in a world until clever energy will + * be added. After this value energy objects will be stopped to add until it's + * amount will be less then minPercent. These two configs create cyclical + * energy objects adding to the world. + */ + maxPercent: .2, + /** + * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects + * in a world after which energy objects will turn on (be added to the world again). + */ + minPercent: .15 +}; + +module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js new file mode 100644 index 0000000..9a27d32 --- /dev/null +++ b/client/src/manager/plugins/objects/Objects.js @@ -0,0 +1,86 @@ +/** + * Manager's plugin, which add energy objects to the world. Such objects + * may be joined together to get more energy + * + * @author flatline + */ +const Dots = require('./../../../share/Dots'); +const Helper = require('./../../../../../common/src/Helper'); +const Config = require('./Config'); +const Organism = require('./../../plugins/organisms/Organism').Organism; +const OBJECT_TYPES = require('./../../../view/World').OBJECT_TYPES; + +let color = 0; +// +// We have to add object types to global types storage +// +OBJECT_TYPES.TYPE_ENERGY0 = -(Object.keys(OBJECT_TYPES).length + 1); +OBJECT_TYPES.TYPE_ENERGY1 = -(Object.keys(OBJECT_TYPES).length + 1); +OBJECT_TYPES.TYPE_ENERGY2 = -(Object.keys(OBJECT_TYPES).length + 1); +OBJECT_TYPES.TYPE_ENERGY3 = -(Object.keys(OBJECT_TYPES).length + 1); +OBJECT_TYPES.TYPE_ENERGY4 = -(Object.keys(OBJECT_TYPES).length + 1); + +class Objects extends Dots { + constructor(manager) { + super(manager, Config, { + addOnce : false, + checkPeriod: Config.checkPeriod, + minPercent : Config.minPercent, + maxPercent : Config.maxPercent, + blockSize : Config.blockSize, + compareCb : (x, y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 && manager.positions[x][y] <= OBJECT_TYPES.TYPE_ENERGY0, + colorCb : ( ) => {color = Helper.rand(5); return Organism.getColor(4500 + color * 500)}, + setCb : (x, y) => manager.positions[x][y] = -color + }); + } + + // destroy() { + // Helper.unoverride(this._manager, 'onLoop', this._onLoopCb); + // this._manager = null; + // this._onLoopCb = null; + // } + // + // _onLoop(counter) { + // if (counter > 1 || Config.worldStonesPercent === .0) {return} + // + // 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 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 amount} + // if (world.isFree(x, y)) { + // if (world.setDot(x, y, color)) { + // man.positions[x][y] = stone; + // if (++amount >= stones) {return amount} + // } + // } + // } + // + // return amount; + // } +} + +module.exports = Objects; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 1fd1d3a..0cbd989 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,12 +15,11 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .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 + .001, .001, .0001, .001, .001, // var, const, if, loop, operator, + .001, .001, .001, .001, // func, funcCall, return, bracket + .001, .001, // toMem, fromMem, + .001, 2, .001, .001, .001, // lookAt, step, dir, myX, myY, + 1, .001, .00001, .00001 // eat, put, energy, pick ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -47,7 +46,7 @@ const Config = { * {Boolean} If turned on, then organism will be responsible for changing * mutations probabilities. Otherwise these probabilities will be constant */ - orgMutationProbsPerOrg: false, + orgMutationProbsPerOrg: true, /** * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config @@ -56,14 +55,14 @@ const Config = { /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 200000, + 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 * mean, that new organism will not be cloned, if amount of organisms is >= * orgMaxOrgs config. */ - orgKillOnClone: true, + orgKillOnClone: false, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -85,7 +84,7 @@ const Config = { * 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 @@ -100,7 +99,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: 1000000, + orgAlivePeriod: 5000, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, @@ -126,11 +125,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 1000, + orgMaxOrgs: 800, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 1000, + orgStartAmount: 800, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created @@ -140,7 +139,7 @@ const Config = { /** * {Number} Amount of bits for storing a numeric constant inside byte code */ - codeConstBits: 16, + codeConstBits: 8, /** * {Number} The value from -X/2 to X/2, which is used for setting * default value, while organism is delivering. So, if the value is @@ -166,6 +165,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,... + * TODO: remove this config */ codeBitsPerBlock: 10, /** diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 77c9ed5..d8b9912 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -11,7 +11,6 @@ const Helper = require('./../../../../../common/src/Helper'); const OConfig = require('./../../../manager/plugins/organisms/Config'); const EVENT_AMOUNT = require('./../../../share/Events').EVENT_AMOUNT; const VM = require('./../../../vm/VM'); -const DIR = require('./../../../../../common/src/Directions').DIR; const OFFSX = require('./../../../../../common/src/Directions').OFFSX; const DESTROY = 0; @@ -27,13 +26,16 @@ const ORG_EVENTS = { ITERATION }; -const MAX_COLORS = 4000; +const MAX_COLORS = 10000; +const ORG_START_COLOR = 3000; +const ORG_END_COLOR = 4000; +const ORG_COLORS = ORG_START_COLOR - ORG_END_COLOR; const UPDATE_COLOR_PERIOD = 50; class Organism extends Observer { /** * Returns color by index. Index may be increased without limit - * @param {Number} index Color index. Starts from 0 till Number.MAX_VALUE + * @param {Number} index Color index. Starts from 0 till MAX_COLORS * @returns {Number} RGB value */ static getColor(index) { @@ -111,7 +113,12 @@ 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._energyChanges % UPDATE_COLOR_PERIOD === 0 && 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 dir(d) {this._dir = d} @@ -218,7 +225,7 @@ class Organism extends Observer { this.vm = new VM(this, this._operatorCls, OConfig.orgOperatorWeights); this._energy = OConfig.orgStartEnergy; this._startEnergy = OConfig.orgStartEnergy; - this._color = Organism.getColor(MAX_COLORS); + this._color = Organism.getColor(ORG_END_COLOR); this._mutationProbs = OConfig.orgMutationProbs.slice(); this._mutationPeriod = OConfig.orgRainMutationPeriod; this._mutationPercent = OConfig.orgRainMutationPercent; @@ -241,7 +248,7 @@ class Organism extends Observer { } _updateColor() { - this._color = Organism.getColor(OConfig.orgAlivePeriod === 0 ? MAX_COLORS : this._iterations * (MAX_COLORS / OConfig.orgAlivePeriod)); + this._color = Organism.getColor(OConfig.orgAlivePeriod === 0 ? ORG_END_COLOR : this._iterations * (ORG_COLORS / OConfig.orgAlivePeriod) + ORG_START_COLOR); } _updateClone() { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 964c4ad..1815498 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -6,13 +6,16 @@ * * @author flatline */ -const Helper = require('./../../../../../../common/src/Helper'); -const EVENTS = require('./../../../../../src/share/Events').EVENTS; -const OConfig = require('./../Config'); -const Operators = require('./../../../../vm/Operators'); -const Num = require('./../../../../vm/Num'); -const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; -const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; +const Helper = require('./../../../../../../common/src/Helper'); +const EVENTS = require('./../../../../../src/share/Events').EVENTS; +const OConfig = require('./../Config'); +const Operators = require('./../../../../vm/Operators'); +const Num = require('./../../../../vm/Num'); +const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; +const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; +const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; + +const NORMALIZE_NO_DIR = Helper.normalizeNoDir; /** * {Function} Is created to speed up this function call. constants are run @@ -23,7 +26,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; - this.OPERATOR_AMOUNT = 16; + this.OPERATOR_AMOUNT = 20; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -32,16 +35,24 @@ class OperatorsDos extends Operators { Operators.compile(this.OPERATOR_AMOUNT); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); - this.LENS.push(Num.MAX_BITS - bitsPerOp); + this.LENS.push(Num.MAX_BITS - bitsPerOp); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - bitsPerOp); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this._compileLookAt(); // 11 this._compileStep(); // 12 this._compileDir(); // 13 this._compileMyX(); // 14 this._compileMyY(); // 15 + this._compileEat(); // 16 + this._compilePut(); // 17 + this._compileEnergy(); // 18 + this._compilePick(); // 19 } /** @@ -64,7 +75,7 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { for (let v2 = 0; v2 < vars; v2++) { - eval(`OperatorsDos.global.fn = function (line) { + eval(`OperatorsDos.global.fn = function lookAt(line) { const vars = this.vars; const x = (vars[${v1}] + .5) << 0; const y = (vars[${v2}] + .5) << 0; @@ -88,7 +99,7 @@ class OperatorsDos extends Operators { * string: step */ static _compileStep() { - eval(`OperatorsDos.global.fn = function (line, num, org) { + eval(`OperatorsDos.global.fn = function step(line, num, org) { this._obs.fire(${EVENTS.STEP}, org, org.x, org.y, org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); return ++line; }`); @@ -114,7 +125,7 @@ class OperatorsDos extends Operators { const dirs = OFFSX.length; for (let v0 = 0; v0 < vars; v0++) { - eval(`Operators.global.fn = function (line, num, org) { + eval(`Operators.global.fn = function dir(line, num, org) { org.dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; return ++line; }`); @@ -140,7 +151,7 @@ class OperatorsDos extends Operators { const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { - eval(`Operators.global.fn = function (line, num, org) { + eval(`Operators.global.fn = function myX(line, num, org) { this.vars[${v0}] = org.x; return ++line; }`); @@ -166,7 +177,7 @@ class OperatorsDos extends Operators { const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { - eval(`Operators.global.fn = function (line, num, org) { + eval(`Operators.global.fn = function myY(line, num, org) { this.vars[${v0}] = org.y; return ++line; }`); @@ -174,6 +185,172 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'eat' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110000 01... + * string: eat(v1) + */ + static _compileEat() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function eat(line, num, org) { + const eat = this.vars[${v0}]; + if (eat <= 0) {return ++line} + let x; + let y; + [x, y] = NORMALIZE_NO_DIR(org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); + const victim = this._positions[x][y]; + + if (victim < 0) {return ++line} // World object found. We can't eat objects + if (victim === 0) { // Energy found + org.energy += this._world.grabDot(x, y, eat); + this._obs.fire(EVENTS.EAT_ENERGY, eat); + return ++line; + } + if (victim.energy <= eat) { // Organism found + this._obs.fire(EVENTS.KILL_EAT, victim); + org.energy += victim.energy; + // + // 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 + // + victim.destroy(); + return ++line; + } + + this._obs.fire(EVENTS.EAT_ORG, victim, eat); + org.energy += eat; + victim.energy -= eat; + + return ++line; + }`); + ops[h(`${'110000'}${b(v0, bpv)}`)] = this.global.fn; + } + } + + /** + * Compiles all variants of 'put' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110001 01... + * string: put(v1) + */ + static _compilePut() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + const event = EVENTS.PUT_ENERGY; + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function put(line, num, org) { + const put = this.vars[${v0}]; + if (put <= 0) {return ++line} + let x; + let y; + [x, y] = NORMALIZE_NO_DIR(org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); + const color = this._world.data[x][y]; + if (color > 0) {return ++line} + + this._world.setDot(x, y, put); + this._obs.fire(${event}, put); + org.energy -= put; + return ++line; + }`); + ops[h(`${'110001'}${b(v0, bpv)}`)] = this.global.fn; + } + } + + /** + * Compiles all variants of 'energy' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110010 01... + * string: energy(v1) + */ + static _compileEnergy() { + const ops = this._compiledOperators; + const h = this._toHexNum; + + eval(`Operators.global.fn = function energy(line, num, org) { + const poses = this._positions; + const world = this._world; + let coef = 0; + for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { + for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { + if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { + coef += -poses[x][y]; + world.setDot(x, y, 0); + poses[x][y] = 0; + } + } + } + org.energy += (coef * 0x00ff00); + return ++line; + }`); + ops[h(`${'110010'}`)] = this.global.fn; + } + + /** + * Compiles all variants of 'pick' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110011 01... + * string: pick(v1) + */ + static _compilePick() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + const dirs = OFFSX.length; + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function pick(line, num, org) { + const poses = this._positions; + const world = this._world; + const x = org.x + OFFSX[org.dir]; + const y = org.y + OFFSY[org.dir]; + if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { + const dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; + const dx = org.x + OFFSX[dir]; + const dy = org.y + OFFSY[dir]; + if (IN_WORLD(dx, dy) && world.data[dx][dy] === 0) { + poses[dx][dy] = poses[x][y]; + poses[x][y] = 0; + world.setDot(dx, dy, world.data[x][y]); + world.setDot(x, y, 0); + } + } + return ++line; + }`); + ops[h(`${'110011'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** @@ -215,7 +392,6 @@ class OperatorsDos extends Operators { */ this._obs = obs; this._world = man.world; - this._organisms = man.organisms; this._positions = man.positions; } @@ -229,7 +405,6 @@ class OperatorsDos extends Operators { super.destroy(); this._world = null; - this._organisms = null; this._positions = null; this._obs = null; this._ret = null; diff --git a/client/src/manager/plugins/stones/Config.js b/client/src/manager/plugins/stones/Config.js new file mode 100644 index 0000000..624e0ba --- /dev/null +++ b/client/src/manager/plugins/stones/Config.js @@ -0,0 +1,21 @@ +/** + * Configuration of Stones plugin + * + * @author flatline + */ +const Config = { + /** + * {Number} size of one stone block in dots + */ + blockSize: 300, + /** + * {Number} Index of stone color. Starts from 0. Ends with Organism.MAX_COLORS + */ + colorIndex: 1800, + /** + * {Number} Percent from all dots in a world until stones will be added. + */ + maxPercent: .15 +}; + +module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/stones/Stones.js b/client/src/manager/plugins/stones/Stones.js new file mode 100644 index 0000000..42a78ce --- /dev/null +++ b/client/src/manager/plugins/stones/Stones.js @@ -0,0 +1,79 @@ +/** + * Manager's plugin, which add stones to the world + * + * @author flatline + */ +const Dots = require('./../../../share/Dots'); +const Config = require('./Config'); +const OBJECT_TYPES = require('../../../view/World').OBJECT_TYPES; +// +// We have to add stone type to global types storage +// +OBJECT_TYPES.TYPE_STONE = -(Object.keys(OBJECT_TYPES).length + 1); + +class Stones extends Dots{ + constructor(manager) { + super(manager, Config, { + addOnce : true, + maxPercent : Config.maxPercent, + colorIndex : Config.colorIndex, + blockSize : Config.blockSize, + setCb : (x, y) => manager.positions[x][y] = OBJECT_TYPES.TYPE_STONE + }); + // 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.worldStonesPercent === .0) {return} + // + // 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 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 amount} + // if (world.isFree(x, y)) { + // if (world.setDot(x, y, color)) { + // man.positions[x][y] = stone; + // if (++amount >= stones) {return amount} + // } + // } + // } + // + // return amount; + // } +} + +module.exports = Stones; \ No newline at end of file diff --git a/client/src/share/Config.js b/client/src/share/Config.js index d70a4bb..43ae5f3 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -38,8 +38,9 @@ ClientConfig.init({ 'organisms/dos/Code2String', 'Config', 'client/Client', - 'Energy', - 'Stones', + 'energy/Energy', + 'stones/Stones', + 'objects/Objects', 'status/console/Console', IS_NODE_JS ? '' : 'status/charts/Charts', 'ips/Ips', @@ -67,43 +68,6 @@ ClientConfig.init({ * calculations). */ 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 - */ - worldEnergyCheckPeriod: 5000, - /** - * {Number} size of one clever energy block in dots - */ - worldEnergyBlockSize: 10, - /** - * {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 - * be less then worldEnergyMinPercent. These two configs create cyclical - * energy adding to the world. - */ - 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 - * world again). - */ - worldEnergyMinPercent: .28, - /** - * {Number} Percent of stones in a world. Percent from world size: - * stoneAmount = worldStonesPercent * worldWidth * worldHeight - */ - worldStonesPercent: .25, - /** - * {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/share/Dots.js b/client/src/share/Dots.js new file mode 100644 index 0000000..b30339e --- /dev/null +++ b/client/src/share/Dots.js @@ -0,0 +1,120 @@ +/** + * Manager's plugin. Base class for adding dots to the world. It may + * be energy, stones, etc... You have to inherit your class to have + * your custom object. + * + * @author flatline + */ +const Helper = require('../../../common/src/Helper'); +const Configurable = require('../../../common/src/Configurable'); +const Config = require('./Config').Config; +const Organism = require('../manager/plugins/organisms/Organism').Organism; + +class Dots extends Configurable { + /** + * Creates dots object. You have to inherit your class from this one + * to have specified type of object. For example: stone or energy. + * @param {Manager} manager Parent manager instance + * @param {Config} config Reference to configuration object + * @param {Object} cfg Configuration for current dots class + * @param {Object} api plugin's API + */ + constructor(manager, config, cfg, api = {}) { + super(manager, {Config, cfg: config}, api); + + this.manager = manager; + this._cfg = cfg; + this._onIterationCb = this.onIteration.bind(this); + + Helper.override(manager, 'onIteration', this._onIterationCb); + } + + destroy() { + Helper.unoverride(this.manager, 'onIteration', this._onIterationCb); + this._onIterationCb = null; + this._cfg = null; + this.manager = null; + } + + onIteration(counter) { + const cfg = this._cfg; + // + // We have to add dots only once + // + if (cfg.addOnce && counter < 1 && cfg.maxPercent !== .0) {this._addDots(); return false} + // + // We have to add dots every time, when minimum percent of dots is reached + // + if (cfg.checkPeriod === 0 || counter % cfg.checkPeriod !== 0) {return false} + + const dotsPercent = this._getDotsPercent(cfg.compareCb); + if (dotsPercent > cfg.minPercent) {return dotsPercent} + this._addDots(); + + return dotsPercent; + } + + /** + * Returns percent of object with specified type in a world. Percent is + * calculating comparing with all dots in a world (100%) + * @param {Function} compareCb Compare function. Returns true/false + * @return {Number} Percent + */ + _getDotsPercent(compareCb) { + let dots = 0; + const width = Config.worldWidth; + const height = Config.worldHeight; + + for (let x = 0; x < width; x++) { + for (let y = 0; y < height; y++) { + if (compareCb(x, y)) {++dots} + } + } + + return dots / (width * height); + } + + _addDots() { + const dots = this._cfg.maxPercent * Config.worldWidth * Config.worldHeight; + let amount = 0; + let attempts = 0; + while (amount < dots && attempts < 100) { + const startAmount = amount; + amount = this._addDotsBlock(amount, dots); + if (startAmount === amount) { + attempts++; + } else { + attempts = 0; + } + } + } + + _addDotsBlock(amount, dots) { + const width = Config.worldWidth; + const height = Config.worldHeight; + const color = Organism.getColor(this._cfg.colorIndex); + const man = this.manager; + const world = man.world; + const blockSize = this._cfg.blockSize; + const setCb = this._cfg.setCb; + const colorCb = this._cfg.colorCb; + let x = Helper.rand(width); + let y = Helper.rand(height); + + for (let i = 0; i < blockSize; 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 (world.isFree(x, y)) { + if (world.setDot(x, y, colorCb ? colorCb(x, y) : color)) { + setCb && setCb(x,y); + if (++amount >= dots) {return amount} + } + } + } + + return amount; + } +} + +module.exports = Dots; \ No newline at end of file diff --git a/client/src/view/Canvas.js b/client/src/view/Canvas.js index 20b405a..a6a9af2 100644 --- a/client/src/view/Canvas.js +++ b/client/src/view/Canvas.js @@ -99,6 +99,7 @@ class Canvas { })); el.title = 'fullscreen'; + // TODO: use addEventListener(). el.onclick = () => { this._panZoom.zoomAbs(0, 0, 1.0); this._panZoom.moveTo(0, 0); diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 4077b41..9302c4e 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -25,12 +25,12 @@ class Operators { * {Number} Bit related constants */ this.FOUR_BITS = 4; - this.CONDITION_BITS = 2; + this.CONDITION_BITS = 4; this.FUNC_NAME_BITS = 10; /** * {Array} Available conditions for if operator */ - this._CONDITIONS = ['<', '>', '===', '!==']; + this._CONDITIONS = ['+', '-', '*', '/', '%', '&', '|', '^', '>>', '<<', '>>>', '<', '>', '===', '!==', '<=']; /** * {Array} Available operators for math calculations */ @@ -133,7 +133,7 @@ class Operators { for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { - eval(`Operators.global.fn = function (line) { + eval(`Operators.global.fn = function vars(line) { this.vars[${v0}] = this.vars[${v1}]; return ++line; }`); @@ -162,7 +162,7 @@ class Operators { const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { - eval(`Operators.global.fn = function (line, num) { + eval(`Operators.global.fn = function consts(line, num) { this.vars[${v0}] = num << ${bits1var} >>> ${bits}; return ++line; }`); @@ -176,9 +176,9 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 6 xx xx 2 - * number: 100010 00 01 00... - * string: if (v0 < v1) { + * bits : 6 xx xx 4 + * number: 100010 00 01 0000... + * string: if (v0 + v1) { */ static _compileIf() { const bpv = OConfig.codeBitsPerVar; @@ -190,7 +190,7 @@ class Operators { for (let c = 0; c < Math.pow(2, this.CONDITION_BITS); c++) { for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { - eval(`Operators.global.fn = function (line) { + eval(`Operators.global.fn = function cond(line) { if (this.vars[${v0}] ${this._CONDITIONS[c]} this.vars[${v1}]) {return ++line} return this.offs[line] === line ? ++line : this.offs[line]; }`); @@ -220,7 +220,7 @@ class Operators { for (let c = 0; c < Math.pow(2, this.CONDITION_BITS); c++) { for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { - eval(`Operators.global.fn = function (line) { + eval(`Operators.global.fn = function loop(line) { if (this.vars[${v0}] ${this._CONDITIONS[c]} this.vars[${v1}]) {return ++line} return this.offs[line] === line ? ++line : this.offs[line]; }`); @@ -246,12 +246,13 @@ class Operators { const h = this._toHexNum; const b = this._toBinStr; const vars = Math.pow(2, bpv); + const opsLen = Math.pow(2, this.FOUR_BITS); - for (let op = 0; op < Math.pow(2, this.FOUR_BITS); op++) { + for (let op = 0; op < opsLen; op++) { for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { for (let v2 = 0; v2 < vars; v2++) { - eval(`Operators.global.fn = function (line) { + eval(`Operators.global.fn = function math(line) { ${this._OPERATORS[op](v0, v1, v2)} return ++line; }`); @@ -276,7 +277,7 @@ class Operators { const ops = this._compiledOperators; const h = this._toHexNum; - eval(`Operators.global.fn = function (line) {return this.offs[line] === line ? ++line : this.offs[line]}`); + eval(`Operators.global.fn = function func(line) {return this.offs[line] === line ? ++line : this.offs[line]}`); ops[h(`${'100101'}`)] = this.global.fn; } @@ -300,7 +301,7 @@ class Operators { const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar; const opBits = Num.BITS_PER_OPERATOR; - eval(`Operators.global.fn = function (line, num) { + eval(`Operators.global.fn = function call(line, num) { const data = num << ${opBits}; const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? this.vars[(data >>> ${varBits} + .5) << 0] : data >>> ${fnBits}]; if (typeof offs !== 'undefined') { @@ -327,7 +328,7 @@ class Operators { const h = this._toHexNum; const vars = Math.pow(2, OConfig.codeBitsPerVar); - eval(`Operators.global.fn = function (line) { + eval(`Operators.global.fn = function ret(line) { if (this.stack.length > 0) { const stackVars = this.stack.pop(); const vars = this.vars; @@ -356,7 +357,7 @@ class Operators { const vars = Math.pow(2, OConfig.codeBitsPerVar); const opMask = Num.OPERATOR_MASK_OFF; - eval(`Operators.global.fn = function (line, num, org, lines) { + eval(`Operators.global.fn = function bracket(line, num, org, lines) { const startLine = this.offs[line]; const operator = (lines[startLine] & ${opMask}) >>> Num.VAR_BITS_OFFS; if (operator === 0x3) {return this.offs[line]} // loop @@ -395,7 +396,7 @@ class Operators { for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { - eval(`Operators.global.fn = function (line, num, org) { + eval(`Operators.global.fn = function toMem(line, num, org) { const offs = ((this.vars[${v0}] + .5) << 0) >>> 0; org.mem[offs > ${memLen} ? ${memLen} : offs] = this.vars[${v1}]; return ++line; @@ -421,13 +422,13 @@ class Operators { const h = this._toHexNum; const b = this._toBinStr; const vars = Math.pow(2, bpv); - const memLen = Math.pow(2, OConfig.orgMemBits); + const memLen = Math.pow(2, OConfig.orgMemBits) - 1; for (let v0 = 0; v0 < vars; v0++) { for (let v1 = 0; v1 < vars; v1++) { - eval(`Operators.global.fn = function (line, num, org) { + eval(`Operators.global.fn = function fromMem(line, num, org) { const offs = ((this.vars[${v1}] + .5) << 0) >>> 0; - this.vars[${v0}] = org.mem[offs >= ${memLen} ? ${memLen-1} : offs]; + this.vars[${v0}] = org.mem[offs > ${memLen} ? ${memLen} : offs]; return ++line; }`); ops[h(`${'101010'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; From c68350f735bfaa85af71a01753aa4985499a1a33 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 12 Apr 2018 15:20:16 +0300 Subject: [PATCH 08/88] fixed an issue with negative energy added dependency to organism size. as big as more energy grabs added clone dependency from organism size --- .../src/manager/plugins/organisms/Config.js | 20 +++++++++---------- .../src/manager/plugins/organisms/Organism.js | 5 +---- .../manager/plugins/organisms/Organisms.js | 2 +- .../plugins/organisms/dos/Operators.js | 5 ++++- .../plugins/organisms/dos/Organisms.js | 2 +- client/src/vm/VM.js | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 0cbd989..6722e1d 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,11 +15,11 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .001, .001, .0001, .001, .001, // var, const, if, loop, operator, - .001, .001, .001, .001, // func, funcCall, return, bracket - .001, .001, // toMem, fromMem, - .001, 2, .001, .001, .001, // lookAt, step, dir, myX, myY, - 1, .001, .00001, .00001 // eat, put, energy, pick + .01, .01, .01, .0001, .01, // var, const, if, loop, operator, + .01, .01, .01, .01, // func, funcCall, return, bracket + .01, .01, // toMem, fromMem, + .01, .1, .01, .01, .01, // lookAt, step, dir, myX, myY, + .1, .01, .0001, .0001 // eat, put, energy, pick ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -51,18 +51,18 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 300, + orgCloneMinAge: 1000, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 2000000, + orgCloneMinEnergy: 200000, /** * {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 @@ -125,11 +125,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 800, + orgMaxOrgs: 1000, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 800, + 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 diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index d8b9912..0af49d5 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -252,7 +252,7 @@ class Organism extends Observer { } _updateClone() { - if (this._iterations > OConfig.orgCloneMinAge && this._energy > OConfig.orgCloneMinEnergy) {this.fire(CLONE, this)} + if (this._iterations > OConfig.orgCloneMinAge && this._energy > OConfig.orgCloneMinEnergy * this.vm.size) {this.fire(CLONE, this)} } /** @@ -276,9 +276,6 @@ class Organism extends Observer { * @return {Boolean} false means that organism was destroyed. */ _updateEnergy() { - // - // this.vm === null means, that organism has already destroyed - // if (this._energy < 1 && this.vm) { this.fire(KILL_NO_ENERGY, this); this.destroy(); diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index af8b78c..bcaa17f 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -308,7 +308,7 @@ class Organisms extends Configurable { */ _updateTournament(counter) { const period = OConfig.orgTournamentPeriod; - return counter % period === 0 && this.organisms.length > 0 || period !== 0 && this._killInTour(); + return counter % period === 0 && this.organisms.length > 0 && period !== 0 && this._killInTour(); } _updateRandomOrgs(counter) { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 1815498..f920fd0 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -9,7 +9,9 @@ const Helper = require('./../../../../../../common/src/Helper'); const EVENTS = require('./../../../../../src/share/Events').EVENTS; const OConfig = require('./../Config'); +const EConfig = require('./../../energy/Config'); const Operators = require('./../../../../vm/Operators'); +const Organism = require('./../../../plugins/organisms/Organism').Organism; const Num = require('./../../../../vm/Num'); const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; @@ -290,6 +292,7 @@ class OperatorsDos extends Operators { static _compileEnergy() { const ops = this._compiledOperators; const h = this._toHexNum; + const energy = Organism.getColor(EConfig.colorIndex); eval(`Operators.global.fn = function energy(line, num, org) { const poses = this._positions; @@ -304,7 +307,7 @@ class OperatorsDos extends Operators { } } } - org.energy += (coef * 0x00ff00); + org.energy += (coef * ${energy}); return ++line; }`); ops[h(`${'110010'}`)] = this.global.fn; diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index b7e2e2a..23cb449 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -77,7 +77,7 @@ class Organisms extends BaseOrganisms { // // Clone percent is always 0.5 // - let energy = (orgEnergy * .5 + .5) << 0; // analog of Math.round() + let energy = (orgEnergy * .5 + .5) << 0 >>> 0; // analog of Math.round() // // This is very special/rare case, when organisms cheating by creating // ancestors and put all energy into them at the same time resetting diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index b629add..a873286 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -110,7 +110,7 @@ class VM extends Observer { // // Every operator has it's own weight // - org.energy -= weights[op]; + org.energy -= (weights[op] * codeLen); // // We reach the end of the script and have to run it from the beginning // From 3323e90c7c4819b64a992f2ac38d57d45d482ecc Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 13 Apr 2018 13:32:42 +0300 Subject: [PATCH 09/88] removed comments fixed an issue with unreachable objects fixed an issue with killing organisms --- client/src/manager/plugins/energy/Energy.js | 71 ------------------- client/src/manager/plugins/objects/Objects.js | 50 +------------ .../src/manager/plugins/organisms/Config.js | 20 +++--- .../manager/plugins/organisms/Organisms.js | 2 +- client/src/manager/plugins/stones/Stones.js | 53 -------------- 5 files changed, 12 insertions(+), 184 deletions(-) diff --git a/client/src/manager/plugins/energy/Energy.js b/client/src/manager/plugins/energy/Energy.js index 5fb7f46..119ca55 100644 --- a/client/src/manager/plugins/energy/Energy.js +++ b/client/src/manager/plugins/energy/Energy.js @@ -18,83 +18,12 @@ class Energy extends Dots { blockSize : Config.blockSize, compareCb : (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0 }); - //this._manager = manager; - //this._onIterationCb = this._onIteration.bind(this); - - //Helper.override(manager, 'onIteration', this._onIterationCb); } onIteration(counter) { const energy = super.onIteration(counter); energy !== false && this.manager.fire(EVENTS.WORLD_ENERGY, energy); } - - // destroy() { - // Helper.unoverride(this._manager, 'onIteration', this._onIterationCb); - // this._manager = null; - // this._onIterationCb = null; - // } - // - // _onIteration(counter) { - // if (Config.worldEnergyCheckPeriod === 0 || counter % Config.worldEnergyCheckPeriod !== 0) {return} - // - // let energy = this._getEnergyPercent(); - // - // this._manager.fire(EVENTS.WORLD_ENERGY, energy); - // if (energy > Config.worldEnergyMinPercent) {return} - // - // const maxEnergy = Config.worldEnergyMaxPercent * Config.worldWidth * Config.worldHeight; - // 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 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 (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; - // const height = Config.worldHeight; - // - // for (let x = 0; x < width; x++) { - // for (let y = 0; y < height; y++) { - // if (world.getDot(x, y) > 0) {++energy} - // } - // } - // - // return energy / (width * height); - // } } module.exports = Energy; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js index 9a27d32..0a4c476 100644 --- a/client/src/manager/plugins/objects/Objects.js +++ b/client/src/manager/plugins/objects/Objects.js @@ -29,58 +29,10 @@ class Objects extends Dots { maxPercent : Config.maxPercent, blockSize : Config.blockSize, compareCb : (x, y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 && manager.positions[x][y] <= OBJECT_TYPES.TYPE_ENERGY0, - colorCb : ( ) => {color = Helper.rand(5); return Organism.getColor(4500 + color * 500)}, + colorCb : ( ) => {color = Helper.rand(5) - OBJECT_TYPES.TYPE_ENERGY0; return Organism.getColor(4500 + (color + OBJECT_TYPES.TYPE_ENERGY0) * 500)}, setCb : (x, y) => manager.positions[x][y] = -color }); } - - // destroy() { - // Helper.unoverride(this._manager, 'onLoop', this._onLoopCb); - // this._manager = null; - // this._onLoopCb = null; - // } - // - // _onLoop(counter) { - // if (counter > 1 || Config.worldStonesPercent === .0) {return} - // - // 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 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 amount} - // if (world.isFree(x, y)) { - // if (world.setDot(x, y, color)) { - // man.positions[x][y] = stone; - // if (++amount >= stones) {return amount} - // } - // } - // } - // - // return amount; - // } } module.exports = Objects; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 6722e1d..c8f9a9e 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,11 +15,11 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .01, .01, .01, .0001, .01, // var, const, if, loop, operator, - .01, .01, .01, .01, // func, funcCall, return, bracket - .01, .01, // toMem, fromMem, - .01, .1, .01, .01, .01, // lookAt, step, dir, myX, myY, - .1, .01, .0001, .0001 // eat, put, energy, pick + .001, .001, .001, .00001, .001, // var, const, if, loop, operator, + .001, .001, .001, .001, // func, funcCall, return, bracket + .001, .001, // toMem, fromMem, + .0001, .01, .001, .001, .001, // lookAt, step, dir, myX, myY, + .01, .001, .01, .00001 // eat, put, energy, pick ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -51,18 +51,18 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 1000, + orgCloneMinAge: 300, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 200000, + orgCloneMinEnergy: 20000, /** * {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: true, + orgKillOnClone: false, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -125,11 +125,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 1000, + orgMaxOrgs: 500, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 1000, + orgStartAmount: 500, /** * {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 bcaa17f..382b73c 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -281,7 +281,7 @@ class Organisms extends Configurable { // if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs) { const randOrg = this._randOrg(); - if (randOrg !== org && Math.random() <= org.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} + if (randOrg !== org && Math.random() <= randOrg.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} } if (this.organisms.length < OConfig.orgMaxOrgs) {this._clone(org)} } diff --git a/client/src/manager/plugins/stones/Stones.js b/client/src/manager/plugins/stones/Stones.js index 42a78ce..485aa1a 100644 --- a/client/src/manager/plugins/stones/Stones.js +++ b/client/src/manager/plugins/stones/Stones.js @@ -20,60 +20,7 @@ class Stones extends Dots{ blockSize : Config.blockSize, setCb : (x, y) => manager.positions[x][y] = OBJECT_TYPES.TYPE_STONE }); - // 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.worldStonesPercent === .0) {return} - // - // 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 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 amount} - // if (world.isFree(x, y)) { - // if (world.setDot(x, y, color)) { - // man.positions[x][y] = stone; - // if (++amount >= stones) {return amount} - // } - // } - // } - // - // return amount; - // } } module.exports = Stones; \ No newline at end of file From 502bfbc8087c8f3b372219c8d31ee0c4f090902d Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 13 Apr 2018 19:37:25 +0300 Subject: [PATCH 10/88] added commands: rand, say, listen fixed an issue with real time config change of plugins: Energy, Stones, Objects fixed an issue with function calls --- client/src/manager/plugins/energy/Config.js | 4 +- client/src/manager/plugins/energy/Energy.js | 9 +- client/src/manager/plugins/objects/Config.js | 4 +- client/src/manager/plugins/objects/Objects.js | 4 - .../src/manager/plugins/organisms/Config.js | 3 +- .../src/manager/plugins/organisms/Organism.js | 6 +- .../plugins/organisms/dos/Operators.js | 115 +++++++++++++++++- client/src/manager/plugins/stones/Stones.js | 7 +- client/src/share/Dots.js | 17 +-- client/src/vm/Operators.js | 5 +- client/src/vm/VM.js | 3 + 11 files changed, 138 insertions(+), 39 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 6dbca2b..54d82de 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -24,13 +24,13 @@ const Config = { * be less then minPercent. These two configs create cyclical * energy adding to the world. */ - maxPercent: .3, + maxPercent: .2, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .28 + minPercent: .1 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/energy/Energy.js b/client/src/manager/plugins/energy/Energy.js index 119ca55..5866f3a 100644 --- a/client/src/manager/plugins/energy/Energy.js +++ b/client/src/manager/plugins/energy/Energy.js @@ -10,13 +10,8 @@ const EVENTS = require('./../../../share/Events').EVENTS; class Energy extends Dots { constructor(manager) { super(manager, Config, { - addOnce : false, - checkPeriod: Config.checkPeriod, - minPercent : Config.minPercent, - maxPercent : Config.maxPercent, - colorIndex : Config.colorIndex, - blockSize : Config.blockSize, - compareCb : (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0 + addOnce : false, + compareCb: (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0 }); } diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index 2cf1531..d0be3fa 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -19,12 +19,12 @@ const Config = { * amount will be less then minPercent. These two configs create cyclical * energy objects adding to the world. */ - maxPercent: .2, + maxPercent: .15, /** * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects * in a world after which energy objects will turn on (be added to the world again). */ - minPercent: .15 + minPercent: .1 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js index 0a4c476..6ef6067 100644 --- a/client/src/manager/plugins/objects/Objects.js +++ b/client/src/manager/plugins/objects/Objects.js @@ -24,10 +24,6 @@ class Objects extends Dots { constructor(manager) { super(manager, Config, { addOnce : false, - checkPeriod: Config.checkPeriod, - minPercent : Config.minPercent, - maxPercent : Config.maxPercent, - blockSize : Config.blockSize, compareCb : (x, y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 && manager.positions[x][y] <= OBJECT_TYPES.TYPE_ENERGY0, colorCb : ( ) => {color = Helper.rand(5) - OBJECT_TYPES.TYPE_ENERGY0; return Organism.getColor(4500 + (color + OBJECT_TYPES.TYPE_ENERGY0) * 500)}, setCb : (x, y) => manager.positions[x][y] = -color diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index c8f9a9e..0eeeac9 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -19,7 +19,8 @@ const Config = { .001, .001, .001, .001, // func, funcCall, return, bracket .001, .001, // toMem, fromMem, .0001, .01, .001, .001, .001, // lookAt, step, dir, myX, myY, - .01, .001, .01, .00001 // eat, put, energy, pick + .01, .001, .01, .00001, // eat, put, energy, pick + .01, .0001, .0001 // rand, say, listen ], /** * {Array} Probabilities which used, when mutator decides what to do: diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 0af49d5..eb0f5f5 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -90,8 +90,8 @@ class Organism extends Observer { this._iterations = -1; this._changes = 0; this._item = item; + this._msg = 0; this._energyChanges = 0; - this._fnId = 0; } get id() {return this._id} @@ -108,6 +108,7 @@ class Organism extends Observer { get startEnergy() {return this._startEnergy} get color() {return this._color} get mem() {return this._mem} + get msg() {return this._msg} set x(newX) {this._x = newX} set y(newY) {this._y = newY} @@ -122,6 +123,7 @@ class Organism extends Observer { set startEnergy(e) {this._startEnergy = e} set changes(c) {this._changes = c} set dir(d) {this._dir = d} + set msg(m) {this._msg = m} /** * Runs one code iteration (amount of lines set in Config.codeYieldPeriod) and returns @@ -156,7 +158,6 @@ class Organism extends Observer { changes : this._changes, // 'item' will be added after insertion iterations : this._iterations, - fnId : this._fnId, vm : this.vm.serialize(), energy : this._energy, startEnergy : this._startEnergy, @@ -184,7 +185,6 @@ class Organism extends Observer { this._changes = json.changes; // 'item' will be added after insertion this._iterations = json.iterations; - this._fnId = json.fnId; this.vm.unserialize(json.vm); this._energy = json.energy; this._startEnergy = json.startEnergy; diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index f920fd0..f109c25 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -28,7 +28,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; - this.OPERATOR_AMOUNT = 20; + this.OPERATOR_AMOUNT = 23; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -45,6 +45,9 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - bitsPerOp); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this._compileLookAt(); // 11 this._compileStep(); // 12 @@ -55,6 +58,10 @@ class OperatorsDos extends Operators { this._compilePut(); // 17 this._compileEnergy(); // 18 this._compilePick(); // 19 + this._compileRand(); // 20 + this._compileSay(); // 21 + this._compileListen(); // 22 + } /** @@ -283,7 +290,9 @@ class OperatorsDos extends Operators { * Compiles all variants of 'energy' operator and stores they in * this._compiledOperators map. '...' means, that all other bits are * ignored. Step direction depends on active organism's direction. - * See Organism.dir property. Example: + * See Organism.dir property. If organism calls energy command near + * only one energy object it will not be transformed to energy. + * Example: * * bits : 6 xx * number: 110010 01... @@ -295,19 +304,31 @@ class OperatorsDos extends Operators { const energy = Organism.getColor(EConfig.colorIndex); eval(`Operators.global.fn = function energy(line, num, org) { - const poses = this._positions; - const world = this._world; - let coef = 0; + const poses = this._positions; + const world = this._world; + let oldx = -1; + let oldy = -1; + let coef = 0; + let blocks = 0; for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { coef += -poses[x][y]; + if (blocks++ === 0) { + oldx = x; + oldy = y; + continue; + } world.setDot(x, y, 0); poses[x][y] = 0; } } } - org.energy += (coef * ${energy}); + if (blocks > 1) { + org.energy += (coef * ${energy}); + world.setDot(oldx, oldy, 0); + poses[oldx][oldy] = 0; + } return ++line; }`); ops[h(`${'110010'}`)] = this.global.fn; @@ -354,6 +375,88 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'rand' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx xx + * number: 110100 01 11... + * string: v1 = rand(v3) + */ + static _compileRand() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function rand(line) { + this.vars[${v0}] = Helper.rand(((this.vars[${v1}] + .5) << 0 >>> 0)); + return ++line; + }`); + ops[h(`${'110100'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + } + } + } + + /** + * Compiles all variants of 'say' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110101 01... + * string: say(v1) + */ + static _compileSay() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function rand(line, num, org) { + let x = org.x + OFFSX[org.dir]; + let y = org.y + OFFSY[org.dir]; + IN_WORLD(x, y) && !(this._positions[x][y] <= 0) && (this._positions[x][y].msg = this.vars[${v0}]); + return ++line; + }`); + ops[h(`${'110101'}${b(v0, bpv)}`)] = this.global.fn; + } + } + + /** + * Compiles all variants of 'say' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110110 01... + * string: v1 = listen() + */ + static _compileListen() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function rand(line, num, org) { + this.vars[${v0}] = org.msg; + return ++line; + }`); + ops[h(`${'110110'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** diff --git a/client/src/manager/plugins/stones/Stones.js b/client/src/manager/plugins/stones/Stones.js index 485aa1a..222a731 100644 --- a/client/src/manager/plugins/stones/Stones.js +++ b/client/src/manager/plugins/stones/Stones.js @@ -14,11 +14,8 @@ OBJECT_TYPES.TYPE_STONE = -(Object.keys(OBJECT_TYPES).length + 1); class Stones extends Dots{ constructor(manager) { super(manager, Config, { - addOnce : true, - maxPercent : Config.maxPercent, - colorIndex : Config.colorIndex, - blockSize : Config.blockSize, - setCb : (x, y) => manager.positions[x][y] = OBJECT_TYPES.TYPE_STONE + addOnce: true, + setCb : (x, y) => manager.positions[x][y] = OBJECT_TYPES.TYPE_STONE }); } } diff --git a/client/src/share/Dots.js b/client/src/share/Dots.js index b30339e..446cfa1 100644 --- a/client/src/share/Dots.js +++ b/client/src/share/Dots.js @@ -24,6 +24,7 @@ class Dots extends Configurable { this.manager = manager; this._cfg = cfg; + this._config = config; this._onIterationCb = this.onIteration.bind(this); Helper.override(manager, 'onIteration', this._onIterationCb); @@ -33,22 +34,24 @@ class Dots extends Configurable { Helper.unoverride(this.manager, 'onIteration', this._onIterationCb); this._onIterationCb = null; this._cfg = null; + this._config = null; this.manager = null; } onIteration(counter) { - const cfg = this._cfg; + const cfg = this._cfg; + const config = this._config; // // We have to add dots only once // - if (cfg.addOnce && counter < 1 && cfg.maxPercent !== .0) {this._addDots(); return false} + if (cfg.addOnce && counter < 1 && config.maxPercent !== .0) {this._addDots(); return false} // // We have to add dots every time, when minimum percent of dots is reached // - if (cfg.checkPeriod === 0 || counter % cfg.checkPeriod !== 0) {return false} + if (config.checkPeriod === 0 || counter % config.checkPeriod !== 0) {return false} const dotsPercent = this._getDotsPercent(cfg.compareCb); - if (dotsPercent > cfg.minPercent) {return dotsPercent} + if (dotsPercent > config.minPercent) {return dotsPercent} this._addDots(); return dotsPercent; @@ -75,7 +78,7 @@ class Dots extends Configurable { } _addDots() { - const dots = this._cfg.maxPercent * Config.worldWidth * Config.worldHeight; + const dots = this._config.maxPercent * Config.worldWidth * Config.worldHeight; let amount = 0; let attempts = 0; while (amount < dots && attempts < 100) { @@ -92,10 +95,10 @@ class Dots extends Configurable { _addDotsBlock(amount, dots) { const width = Config.worldWidth; const height = Config.worldHeight; - const color = Organism.getColor(this._cfg.colorIndex); + const color = Organism.getColor(this._config.colorIndex); const man = this.manager; const world = man.world; - const blockSize = this._cfg.blockSize; + const blockSize = this._config.blockSize; const setCb = this._cfg.setCb; const colorCb = this._cfg.colorCb; let x = Helper.rand(width); diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 9302c4e..ff4ca8b 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -298,12 +298,13 @@ class Operators { const h = this._toHexNum; const ifBit = Num.MAX_BITS - 1; const fnBits = Num.MAX_BITS - this.FUNC_NAME_BITS; - const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar; + const funcs = Math.pow(2, this.FUNC_NAME_BITS); + const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar - 1; const opBits = Num.BITS_PER_OPERATOR; eval(`Operators.global.fn = function call(line, num) { const data = num << ${opBits}; - const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? this.vars[(data >>> ${varBits} + .5) << 0] : data >>> ${fnBits}]; + const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data >>> ${fnBits}]; if (typeof offs !== 'undefined') { this.stack.push(line + 1, offs - 1, this.vars.slice()); return offs; diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index a873286..29874f9 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -107,6 +107,9 @@ class VM extends Observer { const num = code[line]; const op = (num & opMask) >>> opOffs; line = opHandlers[num >>> lens[op]].call(operators, line, num, org, code); + if (Number.isNaN(org.energy)) { + debugger; + } // // Every operator has it's own weight // From c12d4967bc7b5ffab2b3ffbd9522fdd6e30a555f Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 14 Apr 2018 11:33:40 +0300 Subject: [PATCH 11/88] added check command #135 --- client/src/manager/plugins/energy/Config.js | 4 +- client/src/manager/plugins/objects/Config.js | 4 +- .../src/manager/plugins/organisms/Config.js | 2 +- .../plugins/organisms/dos/Operators.js | 56 +++++++++++++++-- .../plugins/organisms/dos/Organisms.js | 62 ------------------- client/src/vm/VM.js | 3 - 6 files changed, 55 insertions(+), 76 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 54d82de..99d55e3 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -24,13 +24,13 @@ const Config = { * be less then minPercent. These two configs create cyclical * energy adding to the world. */ - maxPercent: .2, + maxPercent: .1, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .1 + minPercent: .01 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index d0be3fa..bb1ac04 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -19,12 +19,12 @@ const Config = { * amount will be less then minPercent. These two configs create cyclical * energy objects adding to the world. */ - maxPercent: .15, + maxPercent: .1, /** * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects * in a world after which energy objects will turn on (be added to the world again). */ - minPercent: .1 + minPercent: .01 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 0eeeac9..ea6a130 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -20,7 +20,7 @@ const Config = { .001, .001, // toMem, fromMem, .0001, .01, .001, .001, .001, // lookAt, step, dir, myX, myY, .01, .001, .01, .00001, // eat, put, energy, pick - .01, .0001, .0001 // rand, say, listen + .01, .0001, .0001, .001 // rand, say, listen, check ], /** * {Array} Probabilities which used, when mutator decides what to do: diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index f109c25..391037d 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -18,7 +18,13 @@ const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; const NORMALIZE_NO_DIR = Helper.normalizeNoDir; - +/** + * {Number} World object types + */ +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() @@ -28,7 +34,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; - this.OPERATOR_AMOUNT = 23; + this.OPERATOR_AMOUNT = 24; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -48,6 +54,7 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this._compileLookAt(); // 11 this._compileStep(); // 12 @@ -61,7 +68,7 @@ class OperatorsDos extends Operators { this._compileRand(); // 20 this._compileSay(); // 21 this._compileListen(); // 22 - + this._compileCheck(); // 23 } /** @@ -421,7 +428,7 @@ class OperatorsDos extends Operators { const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { - eval(`Operators.global.fn = function rand(line, num, org) { + eval(`Operators.global.fn = function say(line, num, org) { let x = org.x + OFFSX[org.dir]; let y = org.y + OFFSY[org.dir]; IN_WORLD(x, y) && !(this._positions[x][y] <= 0) && (this._positions[x][y].msg = this.vars[${v0}]); @@ -432,7 +439,7 @@ class OperatorsDos extends Operators { } /** - * Compiles all variants of 'say' operator and stores they in + * Compiles all variants of 'listen' operator and stores they in * this._compiledOperators map. '...' means, that all other bits are * ignored. Step direction depends on active organism's direction. * See Organism.dir property. Example: @@ -449,7 +456,7 @@ class OperatorsDos extends Operators { const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { - eval(`Operators.global.fn = function rand(line, num, org) { + eval(`Operators.global.fn = function listen(line, num, org) { this.vars[${v0}] = org.msg; return ++line; }`); @@ -457,6 +464,43 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'check' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 110111 00... + * string: v0 = check() + */ + static _compileCheck() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function check(line, num, org) { + const x = org.x + OFFSX[org.dir]; + const y = org.y + OFFSY[org.dir]; + if (!IN_WORLD(x, y)) {return ++line} + + if (this._positions[x][y] < 0) { + this.vars[${v0}] = this._positions[x][y]; + } else if (this._positions[x][y] === 0) { + this.vars[${v0}] = this._world.getDot(x, y) > 0 ? ENERGY : EMPTY; + } else { + this.vars[${v0}] = ORGANISM; + } + + return ++line; + }`); + ops[h(`${'110111'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 23cb449..3b7747e 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -17,13 +17,6 @@ const OConfig = require('./../Config'); const EVENTS = require('./../../../../share/Events').EVENTS; const Helper = require('./../../../../../../common/src/Helper'); const DIR = require('./../../../../../../common/src/Directions').DIR; -/** - * {Number} World object types - */ -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() @@ -96,9 +89,7 @@ class Organisms extends BaseOrganisms { addOrgHandlers(org) { super.addOrgHandlers(org); - org.on(EVENTS.EAT, this._onEat.bind(this)); org.on(EVENTS.STEP, this._onStep.bind(this)); - org.on(EVENTS.CHECK_AT, this._onCheckAt.bind(this)); } /** @@ -111,47 +102,6 @@ class Organisms extends BaseOrganisms { return new Organism(...args); } - _onEat(org, x, y, ret) { - const eat = ret.ret; - [x, y] = NORMALIZE_NO_DIR(x, y); - const victimOrg = this.positions[x][y]; - // - // World object found. We can't eat objects - // - if (victimOrg < 0) {ret.ret = 0; return} - // - // Energy found - // - if (victimOrg === 0) { - if (eat >= 0) { - ret.ret = this.world.grabDot(x, y, eat); - this.parent.fire(EVENTS.EAT_ENERGY, ret.ret); - } else { - ret.ret = eat; - 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 { - this.parent.fire(EVENTS.EAT_ORG, victimOrg, ret.ret); - victimOrg.energy -= ret.ret; - } - } - _onStep(org, x1, y1, x2, y2) { if (org.energy < 1) {return} const man = this.parent; @@ -194,18 +144,6 @@ class Organisms extends BaseOrganisms { this.move(x1, y1, x2, y2, org); } - _onCheckAt(x, y, ret) { - [x, y] = NORMALIZE_NO_DIR(x, y); - - 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 { // organism - ret.ret = ORGANISM; - } - } - /** * Is called if organism step in from the server or other client (Manager/World). * If step in position is not free or maximum organisms are in the world, then diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index 29874f9..a873286 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -107,9 +107,6 @@ class VM extends Observer { const num = code[line]; const op = (num & opMask) >>> opOffs; line = opHandlers[num >>> lens[op]].call(operators, line, num, org, code); - if (Number.isNaN(org.energy)) { - debugger; - } // // Every operator has it's own weight // From 2157537fdf4deb3d247c3a08d05d286c0c2b0cb5 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 14 Apr 2018 23:47:21 +0300 Subject: [PATCH 12/88] fixed an issue with huge energy put fixed an issue of dynamic organisms amount change added max stack size reach check --- client/src/manager/plugins/energy/Config.js | 4 +- client/src/manager/plugins/objects/Config.js | 2 +- .../manager/plugins/organisms/Organisms.js | 45 ++- .../plugins/organisms/dos/Operators.js | 290 +----------------- client/src/share/Events.js | 3 +- client/src/vm/Operators.js | 7 +- common/src/Config.js | 6 +- common/src/FastArray.js | 3 +- 8 files changed, 62 insertions(+), 298 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 99d55e3..b4e3087 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -24,13 +24,13 @@ const Config = { * be less then minPercent. These two configs create cyclical * energy adding to the world. */ - maxPercent: .1, + maxPercent: .2, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .01 + minPercent: .019 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index bb1ac04..5195f3a 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -24,7 +24,7 @@ const Config = { * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects * in a world after which energy objects will turn on (be added to the world again). */ - minPercent: .01 + minPercent: .019 }; module.exports = Config; \ 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 382b73c..5c60e0b 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -64,17 +64,19 @@ class Organisms extends Configurable { getAmount : ['_apiGetAmount', 'Shows amount of organisms within current Client(Manager)'], getOrganism: ['_apiGetOrganism', 'Returns organism instance by id or int\'s index in an array'] }); - this.organisms = manager.organisms; - this.positions = manager.positions; - this.world = manager.world; + this.organisms = manager.organisms; + this.positions = manager.positions; + this.world = manager.world; - this._mutator = new Mutator(manager, this); - this._onIterationCb = this._onIteration.bind(this); - this._onLoopCb = this._onLoop.bind(this); + this._mutator = new Mutator(manager, this); + this._onIterationCb = this._onIteration.bind(this); + this._onLoopCb = this._onLoop.bind(this); + this._onConfigChange = this._onConfigChange.bind(this); this.reset(); Helper.override(manager, 'onIteration', this._onIterationCb); Helper.override(manager, 'onLoop', this._onLoopCb); + manager.on(EVENTS.CONFIG_CHANGE, this._onConfigChange); } destroy() { @@ -84,13 +86,15 @@ class Organisms extends Configurable { Helper.unoverride(this.parent, 'onIteration', this._onIterationCb); Helper.unoverride(this.parent, 'onLoop', this._onLoopCb); + this.parent.off(EVENTS.CONFIG_CHANGE, this._onConfigChange); this._mutator.destroy(); - this._mutator = null; - this.world = null; - this.positions = null; - this.organisms = null; - this._onIterationCb = null; - this._onLoopCb = null; + this._mutator = null; + this.world = null; + this.positions = null; + this.organisms = null; + this._onConfigChange = null; + this._onIterationCb = null; + this._onLoopCb = null; super.destroy(); } @@ -173,6 +177,22 @@ class Organisms extends Configurable { this._updateCreate(); } + /** + * Is called when global configuration has changed. Tracks if amount of + * organisms has changed and updated this.organisms array + * @param {String} key Unique config key + * @param {*} val New value + */ + _onConfigChange(key, val) { + if (key === 'organisms.orgMaxOrgs') { + const orgs = this.organisms; + if (val < orgs.size) { + for (let i = orgs.size - 1; i >= val; i--) {orgs.get(i) !== null && orgs.get(i).destroy()} + } + orgs.resize(val); + } + } + _tournament(org1 = null, org2 = null) { org1 = org1 || this._randOrg(); org2 = org2 || this._randOrg(); @@ -196,6 +216,7 @@ class Organisms extends Configurable { [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(); + if (!child) {return false} this.onClone(org, child); if (org.energy < 1 || child.energy < 1) {return false} diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 391037d..8aebe3f 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -276,13 +276,19 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function put(line, num, org) { - const put = this.vars[${v0}]; + let put = this.vars[${v0}]; if (put <= 0) {return ++line} - let x; - let y; - [x, y] = NORMALIZE_NO_DIR(org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); - const color = this._world.data[x][y]; - if (color > 0) {return ++line} + let x = org.x + OFFSX[org.dir]; + let y = org.y + OFFSY[org.dir]; + if (!IN_WORLD(x, y)) {return ++line} + if (this._world.data[x][y] > 0) {return ++line} + if (org.energy <= put) { + put = org.energy; + this._world.setDot(x, y, put); + this._obs.fire(${event}, put); + org.destroy(); + return ++line; + } this._world.setDot(x, y, put); this._obs.fire(${event}, put); @@ -503,40 +509,6 @@ class OperatorsDos extends Operators { constructor(offs, vars, obs) { super(offs, vars, obs); - /** - * {Object} These operator handlers should return next script line - * number VM should step to - * TODO: will be removed - */ - // this._OPERATORS_CB = [ - // this.onVar.bind(this), - // this.onConst.bind(this), - // this.onCondition.bind(this), - // this.onLoop.bind(this), - // this.onOperator.bind(this), - // this.onLookAt.bind(this), - // this.onEatLeft.bind(this), - // this.onEatRight.bind(this), - // this.onEatUp.bind(this), - // this.onEatDown.bind(this), - // this.onStepLeft.bind(this), - // this.onStepRight.bind(this), - // this.onStepUp.bind(this), - // this.onStepDown.bind(this), - // this.onFromMem.bind(this), - // this.onToMem.bind(this), - // this.onMyX.bind(this), - // this.onMyY.bind(this), - // this.onCheckLeft.bind(this), - // this.onCheckRight.bind(this), - // this.onCheckUp.bind(this), - // this.onCheckDown.bind(this) - // ]; - /** - * {Object} Reusable object to pass it as a parameter to this.fire(..., ret) - * TODO: should be removed, because this class should have references to world, organisms, positions,... - */ - this._ret = {ret: 0}; /** * {Observer} Observer for sending external events */ @@ -559,244 +531,6 @@ class OperatorsDos extends Operators { this._obs = null; this._ret = null; } - - /** - * Handler of variable assignment operator. 'xx' means, that amount of - * bits depends on configuration. '...' means, that all other bits are - * ignored. Example: - * bits : 8 xx xx - * number: 00000000 00 01... - * desc : var v0 v1 - * string: v0 = v1 - * - * @param {Number} num One bit packed byte code row - * @param {Number} line Current line in DOS code - * @return {Number} Next line number to proceed - */ - onVar(num, line) { - this.vars[Num.getVar0(num)] = this.vars[Num.getVar1(num)]; - return ++line; - } - - /** - * Handler of numeric constant assignment operator. 'xx' means, that amount of - * bits depends on configuration. '...' means, that all other bits are - * ignored. Example: - * bits : 8 xx xx - * number: 00000001 00 01... - * desc : const v0 1 - * string: v0 = 1 - * - * @param {Number} num One bit packed byte code row - * @param {Number} line Current line in DOS code - * @return {Number} Next line number to proceed - */ - onConst(num, line) { - this.vars[Num.getVar0(num)] = Num.getBits(num, this._BITS_AFTER_ONE_VAR, OConfig.codeConstBits); - return ++line; - } - - /** - * Handler of 'if' operator. 'xx' means, that amount of bits depends on - * configuration. '...' means, that all other bits are - * ignored. Offset of closing bracket means row number after, which this - * bracket will be added. Offset of closing bracket is calculating using - * formula: line + offs. Example: - * bits : 8 xx xx 2 xx - * number: 00000010 00 01 00 00... - * desc : if v0 v1 < } - * string: if (v0 < v1) {} - * - * @param {Number} num One bit packed byte code row - * @param {Number} line Current line in DOS code - * @return {Number} Next line number to proceed - */ - onCondition(num, line) { - const cond = Num.getBits(num, this._BITS_AFTER_TWO_VARS, CONDITION_BITS); - const offs = this._getOffs(line, Num.getBits(num, this._BITS_AFTER_TWO_VARS + CONDITION_BITS, OConfig.codeBitsPerBlock)); - - if (CONDITIONS[cond](this.vars[Num.getVar0(num)], this.vars[Num.getVar1(num)])) { - this.offs.push(offs, offs); - return ++line; - } - - return offs; - } - - /** - * Handler of 'while' operator. 'xx' means, that amount of bits depends on - * configuration. '...' means, that all other bits are - * ignored. Offset of closing bracket means row number after, which this - * bracket will be added. Offset of closing bracket is calculating using - * formula: line + offs. Example: - * bits : 8 xx xx 2 xx - * number: 00000011 00 01 00 00... - * desc : while v0 v1 < } - * string: while (v0 < v1) {} - * - * @param {Number} num One bit packed byte code row - * @param {Number} line Current line in DOS code - * @return {Number} Next line number to proceed - */ - onLoop(num, line) { - const cond = Num.getBits(num, this._BITS_AFTER_TWO_VARS, CONDITION_BITS); - const offs = this._getOffs(line, Num.getBits(num, this._BITS_AFTER_TWO_VARS + CONDITION_BITS, OConfig.codeBitsPerBlock)); - - if (CONDITIONS[cond](this.vars[Num.getVar0(num)], this.vars[Num.getVar1(num)])) { - this.offs.push(line, offs); - return ++line; - } - - return offs; - } - - onOperator(num, line) { - const vars = this.vars; - vars[Num.getVar0(num)] = OPERATORS[Num.getBits(num, this._BITS_AFTER_THREE_VARS, FOUR_BITS)](vars[Num.getVar1(num)], vars[Num.getVar2(num)]); - return ++line; - } - - onLookAt(num, line) { - const vars = this.vars; - const x = (vars[Num.getVar1(num)] + .5) << 0; - const y = (vars[Num.getVar2(num)] + .5) << 0; - - if (IN_WORLD(x, y)) { - this._obs.fire(EVENTS.GET_ENERGY, x, y, this._ret); - vars[Num.getVar0(num)] = this._ret.ret; - return ++line; - } - - vars[Num.getVar0(num)] = 0; - 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} - onStepUp(num, line, org) {this.vars[Num.getVar0(num)] = this._step(org, org.x, org.y, org.x, org.y - 1, org.y - 1); return ++line} - onStepDown(num, line, org) {this.vars[Num.getVar0(num)] = this._step(org, org.x, org.y, org.x, org.y + 1, org.y + 1); return ++line} - - onFromMem(num, line, org) { - if (Num.getBits(num, this._BITS_AFTER_TWO_VARS, 1)) { - const offs = (this.vars[Num.getVar1(num)] + .5) << 0; - this.vars[Num.getVar0(num)] = org.mem[offs >= org.mem.length || offs < 0 ? 0 : offs]; - return ++line; - } - - this.vars[Num.getVar0(num)] = org.mem[Num.getBits(num, this._BITS_AFTER_TWO_VARS + 1, OConfig.orgMemBits)]; - return ++line; - } - onToMem(num, line, org) { - if (Num.getBits(num, this._BITS_AFTER_TWO_VARS, 1)) { - const offs = (this.vars[Num.getVar0(num)] + .5) << 0; - org.mem[offs >= org.mem.length || offs < 0 ? 0 : offs] = this.vars[Num.getVar1(num)]; - return ++line; - } - - org.mem[Num.getBits(num, this._BITS_AFTER_TWO_VARS + 1, OConfig.orgMemBits)] = this.vars[Num.getVar0(num)]; - return ++line; - } - - 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) { - 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; - } - - _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; - } - - /** - * Returns offset for closing bracket of block operators like - * "if", "for" and so on. These operators shouldn't overlap each - * other. for example: - * - * for (...) { // 0 - * if (...) { // 1 - * ... // 2 - * } // 3 - * } // 4 - * - * Closing bracket in line 3 shouldn't be after bracket in line 4. - * 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} offs Local offset of closing bracket we want to set - * @returns {Number} - */ - _getOffs(line, offs) { - const offsets = this.offs || [0]; - return line + offs > offsets[offsets.length - 1] ? offsets[offsets.length - 1] : line + offs + 1; - } } OperatorsDos.compile(); diff --git a/client/src/share/Events.js b/client/src/share/Events.js index d099c33..6ecde4f 100644 --- a/client/src/share/Events.js +++ b/client/src/share/Events.js @@ -38,7 +38,8 @@ const EVENTS = { RESET_CODE : 28, CHECK_AT : 29, WORLD_ENERGY : 30, - WORLD_ENERGY_UP : 31 + WORLD_ENERGY_UP : 31, + CONFIG_CHANGE : 32 }; diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index ff4ca8b..93d20cb 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -8,6 +8,7 @@ const OConfig = require('./../manager/plugins/organisms/Config'); const Num = require('./Num'); const OPERATOR_AMOUNT = 11; +const MAX_STACK_SIZE = 10000; class Operators { /** @@ -302,10 +303,14 @@ class Operators { const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar - 1; const opBits = Num.BITS_PER_OPERATOR; - eval(`Operators.global.fn = function call(line, num) { + eval(`Operators.global.fn = function call(line, num, org) { const data = num << ${opBits}; const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data >>> ${fnBits}]; if (typeof offs !== 'undefined') { + if (this.stack.length > MAX_STACK_SIZE * 3) { + org.energy -= org.vm.size; + return ++line; + } this.stack.push(line + 1, offs - 1, this.vars.slice()); return offs; } diff --git a/common/src/Config.js b/common/src/Config.js index 666857a..4c6d318 100644 --- a/common/src/Config.js +++ b/common/src/Config.js @@ -5,8 +5,9 @@ * * @author flatline */ -const _get = require('lodash/get'); -const _set = require('lodash/set'); +const _get = require('lodash/get'); +const _set = require('lodash/set'); +const EVENTS = require('./../../client/src/share/Events').EVENTS; class Config { static init(cfg) { @@ -22,6 +23,7 @@ class Config { */ static set(key, val) { _set(this._cfg, key, val); + man.fire(EVENTS.CONFIG_CHANGE, key, val); return this; } diff --git a/common/src/FastArray.js b/common/src/FastArray.js index 69cc68b..b127d20 100644 --- a/common/src/FastArray.js +++ b/common/src/FastArray.js @@ -106,7 +106,8 @@ class FastArray { this._index = -1; arr.length = indexes.length = (this._size = size); for (let i = 0; i < size; i++) { - (arr[i] === null) && (indexes[++this._index] = i); + typeof arr[i] === 'undefined' && (arr[i] = null); + arr[i] === null && (indexes[++this._index] = i); } } } From a394de714d90643e869a879fdaf7e3c27076ff81 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 18 Apr 2018 20:19:32 +0300 Subject: [PATCH 13/88] added myEnergy command #135 changed base algorithm of evolve (from now as more energy you have as more ancestors you produce) added delay config (worldSpeed) #76 --- client/src/manager/Manager.js | 1 + client/src/manager/plugins/energy/Config.js | 4 +- client/src/manager/plugins/objects/Config.js | 4 +- .../src/manager/plugins/organisms/Config.js | 12 ++-- .../src/manager/plugins/organisms/Organism.js | 4 +- .../manager/plugins/organisms/Organisms.js | 11 ++-- .../plugins/organisms/dos/Operators.js | 57 ++++++++++++++----- client/src/manager/plugins/stones/Config.js | 2 +- client/src/share/Config.js | 8 ++- client/src/vm/VM.js | 2 +- common/src/Helper.js | 8 +++ 11 files changed, 77 insertions(+), 36 deletions(-) diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index 6db88bd..baa9a23 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -270,6 +270,7 @@ class Manager extends Observer { this.onIteration(i, TIMER()); } this.onLoop(this._counter = i, TIMER()); + Helper.delay((1 - Config.worldSpeed) * 100); this.zeroTimeout(this._onLoopCb); } diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index b4e3087..99d55e3 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -24,13 +24,13 @@ const Config = { * be less then minPercent. These two configs create cyclical * energy adding to the world. */ - maxPercent: .2, + maxPercent: .1, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .019 + minPercent: .01 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index 5195f3a..8bde429 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -19,12 +19,12 @@ const Config = { * amount will be less then minPercent. These two configs create cyclical * energy objects adding to the world. */ - maxPercent: .1, + maxPercent: .3, /** * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects * in a world after which energy objects will turn on (be added to the world again). */ - minPercent: .019 + minPercent: .0195 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ea6a130..e0a1bfe 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -20,7 +20,7 @@ const Config = { .001, .001, // toMem, fromMem, .0001, .01, .001, .001, .001, // lookAt, step, dir, myX, myY, .01, .001, .01, .00001, // eat, put, energy, pick - .01, .0001, .0001, .001 // rand, say, listen, check + .01, .0001, .0001, .001, .001 // rand, say, listen, check, myEnergy ], /** * {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: 500, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 20000, + orgCloneMinEnergy: 5000000, /** * {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 @@ -90,7 +90,7 @@ 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: 4000, + orgCrossoverPeriod: 1000, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature @@ -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: 5000, + orgAlivePeriod: 50000, /** * {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 eb0f5f5..576990a 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -202,7 +202,7 @@ class Organism extends Observer { //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); + return this._energy; } destroy() { @@ -252,7 +252,7 @@ class Organism extends Observer { } _updateClone() { - if (this._iterations > OConfig.orgCloneMinAge && this._energy > OConfig.orgCloneMinEnergy * this.vm.size) {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 5c60e0b..0208386 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -51,14 +51,13 @@ class Organisms extends Configurable { * @abstract */ 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)'], @@ -301,10 +300,12 @@ class Organisms extends Configurable { // to clone them. // if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs) { - const randOrg = this._randOrg(); - if (randOrg !== org && Math.random() <= randOrg.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} + //const randOrg = this._randOrg(); + //const rnd = Math.random(); + //if (randOrg !== org && (rnd >= (randOrg.energy / randOrg.vm.size) / this._maxEnergy || rnd <= randOrg.iterations / OConfig.orgAlivePeriod)) {randOrg.destroy()} + this._killInTour(); } - if (this.organisms.length < OConfig.orgMaxOrgs) {this._clone(org)} + if (this.organisms.length < OConfig.orgMaxOrgs && org.vm !== null) {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 8aebe3f..334c891 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -34,7 +34,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; - this.OPERATOR_AMOUNT = 24; + this.OPERATOR_AMOUNT = 25; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -55,20 +55,22 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this._compileLookAt(); // 11 - this._compileStep(); // 12 - this._compileDir(); // 13 - this._compileMyX(); // 14 - this._compileMyY(); // 15 - this._compileEat(); // 16 - this._compilePut(); // 17 - this._compileEnergy(); // 18 - this._compilePick(); // 19 - this._compileRand(); // 20 - this._compileSay(); // 21 - this._compileListen(); // 22 - this._compileCheck(); // 23 + this._compileLookAt(); // 11 + this._compileStep(); // 12 + this._compileDir(); // 13 + this._compileMyX(); // 14 + this._compileMyY(); // 15 + this._compileEat(); // 16 + this._compilePut(); // 17 + this._compileEnergy(); // 18 + this._compilePick(); // 19 + this._compileRand(); // 20 + this._compileSay(); // 21 + this._compileListen(); // 22 + this._compileCheck(); // 23 + this._compileMyEnergy(); // 24 } /** @@ -507,6 +509,32 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'check' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 111000 00... + * string: v0 = myEnergy() + */ + static _compileMyEnergy() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = this._toHexNum; + const b = this._toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function myEnergy(line, num, org) { + this.vars[${v0}] = org.energy; + return ++line; + }`); + ops[h(`${'111000'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** @@ -529,7 +557,6 @@ class OperatorsDos extends Operators { this._world = null; this._positions = null; this._obs = null; - this._ret = null; } } diff --git a/client/src/manager/plugins/stones/Config.js b/client/src/manager/plugins/stones/Config.js index 624e0ba..5ff7cdc 100644 --- a/client/src/manager/plugins/stones/Config.js +++ b/client/src/manager/plugins/stones/Config.js @@ -15,7 +15,7 @@ const Config = { /** * {Number} Percent from all dots in a world until stones will be added. */ - maxPercent: .15 + maxPercent: .05 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 43ae5f3..741d332 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -54,11 +54,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920, + worldWidth: 1920 / 4, /** * {Number} World height */ - worldHeight: 1080, + 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 @@ -68,6 +68,10 @@ ClientConfig.init({ * calculations). */ worldCyclical: true, + /** + * {Number} Speed coefficient. Between 0..1. 1 - max speed, 0 - min. + */ + worldSpeed: 1, /** * {Number} Zoom speed 0..1 */ diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index a873286..b629add 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -110,7 +110,7 @@ class VM extends Observer { // // Every operator has it's own weight // - org.energy -= (weights[op] * codeLen); + org.energy -= weights[op]; // // We reach the end of the script and have to run it from the beginning // diff --git a/common/src/Helper.js b/common/src/Helper.js index 21e8d2d..299d4d8 100644 --- a/common/src/Helper.js +++ b/common/src/Helper.js @@ -8,6 +8,14 @@ const Config = require('./../../client/src/share/Config').Config; const DIR = require('./Directions').DIR; class Helper { + /** + * Makes synchronous delay + * @param {Number} ms Amount of milliseconds to delay + */ + static delay(ms) { + const ts = Date.now(); + while (Date.now() - ts < ms) {} + } /** * Calculates unique id for world's coordinates. For the same x,y * id will be the same. From bb28414642e597e8380d241e16fbc9d2f8986e6a Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 24 Apr 2018 19:20:44 +0300 Subject: [PATCH 14/88] fixed big maps rendering #124 --- client/src/manager/Manager.js | 2 +- client/src/manager/plugins/energy/Config.js | 10 ++- client/src/manager/plugins/objects/Config.js | 2 +- client/src/manager/plugins/objects/Objects.js | 14 +++- .../src/manager/plugins/organisms/Config.js | 58 +++++++------- .../src/manager/plugins/organisms/Organism.js | 6 +- .../manager/plugins/organisms/Organisms.js | 14 ++-- .../plugins/organisms/dos/Operators.js | 64 ++++++++++----- client/src/manager/plugins/stones/Config.js | 2 +- client/src/view/Canvas.js | 80 ++++++++++++++----- client/src/vm/VM.js | 2 +- 11 files changed, 166 insertions(+), 88 deletions(-) diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index baa9a23..f3ec623 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -270,7 +270,7 @@ class Manager extends Observer { this.onIteration(i, TIMER()); } this.onLoop(this._counter = i, TIMER()); - Helper.delay((1 - Config.worldSpeed) * 100); + Helper.delay((1 - Config.worldSpeed) * 60); this.zeroTimeout(this._onLoopCb); } diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 99d55e3..4a4daab 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -17,20 +17,24 @@ const Config = { * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS * constant for details */ - colorIndex: 9174, + colorIndex: 10000, /** * {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 * be less then minPercent. These two configs create cyclical * energy adding to the world. */ - maxPercent: .1, + maxPercent: .3,//.0107, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .01 + minPercent: .005, + /** + * {Number} Amount of energy in one dot + */ + energyAmount: 1000, }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index 8bde429..fa81649 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -24,7 +24,7 @@ const Config = { * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects * in a world after which energy objects will turn on (be added to the world again). */ - minPercent: .0195 + minPercent: .1 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js index 6ef6067..1b37220 100644 --- a/client/src/manager/plugins/objects/Objects.js +++ b/client/src/manager/plugins/objects/Objects.js @@ -9,8 +9,6 @@ const Helper = require('./../../../../../common/src/Helper'); const Config = require('./Config'); const Organism = require('./../../plugins/organisms/Organism').Organism; const OBJECT_TYPES = require('./../../../view/World').OBJECT_TYPES; - -let color = 0; // // We have to add object types to global types storage // @@ -20,13 +18,21 @@ OBJECT_TYPES.TYPE_ENERGY2 = -(Object.keys(OBJECT_TYPES).length + 1); OBJECT_TYPES.TYPE_ENERGY3 = -(Object.keys(OBJECT_TYPES).length + 1); OBJECT_TYPES.TYPE_ENERGY4 = -(Object.keys(OBJECT_TYPES).length + 1); +const GET_COLOR = (index) => Organism.getColor(8500 + (Math.abs(index) + OBJECT_TYPES.TYPE_ENERGY0) * 500); +const COLOR_INDEX = OBJECT_TYPES.TYPE_ENERGY0; +const COLOR_RGB = GET_COLOR(COLOR_INDEX); + class Objects extends Dots { + static getColor(index) { + return GET_COLOR(index); + } + constructor(manager) { super(manager, Config, { addOnce : false, compareCb : (x, y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 && manager.positions[x][y] <= OBJECT_TYPES.TYPE_ENERGY0, - colorCb : ( ) => {color = Helper.rand(5) - OBJECT_TYPES.TYPE_ENERGY0; return Organism.getColor(4500 + (color + OBJECT_TYPES.TYPE_ENERGY0) * 500)}, - setCb : (x, y) => manager.positions[x][y] = -color + colorCb : ( ) => COLOR_RGB, + setCb : (x, y) => manager.positions[x][y] = COLOR_INDEX }); } } diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index e0a1bfe..8f5f0bb 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, .001, .00001, .001, // var, const, if, loop, operator, - .001, .001, .001, .001, // func, funcCall, return, bracket - .001, .001, // toMem, fromMem, - .0001, .01, .001, .001, .001, // lookAt, step, dir, myX, myY, - .01, .001, .01, .00001, // eat, put, energy, pick - .01, .0001, .0001, .001, .001 // rand, say, listen, check, myEnergy + .001, .001, .001, .001, .001, // var, const, if, loop, operator, + .0001, .0001, .0001, .0001, // func, funcCall, return, bracket + .001, .001, // toMem, fromMem, + .00001, .1, .001, .001, .001, // lookAt, step, dir, myX, myY, + .01, .0001, .001, .0001, // eat, put, energy, pick + .001, .00001, .00001, .0001, .001 // rand, say, listen, check, myEnergy ], /** * {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: 500, + orgCloneMinAge: 100, /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 5000000, + orgCloneMinEnergy: 80000, /** * {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: true, + orgKillOnClone: false, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -90,17 +90,27 @@ 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: 0, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 5000, + orgRandomOrgPeriod: 0, /** * {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: 50000, + orgAlivePeriod: 10000, + /** + * {Number} Maximum energy organism may reach collecting energy + */ + orgMaxEnergy: 100000, + /** + * {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, /** * {Number} Size of organism stack (internal memory) in bits. Real amount of * organism's internal memory will be 2^orgMemBits. Example: if orgMemBits=3, @@ -126,17 +136,19 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 500, + orgMaxOrgs: 200, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 500, + 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 - * by operator and not by evolution. + * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef + * will be used during it's energy grabbing by system. We use this approach, + * because our CPU's are slow and organisms with big codes are very slow. But + * it's possible for organisms to go outside the limit by inventing new + * effective mechanisms of energy obtaining. */ - orgStartEnergy: 90000000, + codeMaxSize: 300, /** * {Number} Amount of bits for storing a numeric constant inside byte code */ @@ -173,15 +185,7 @@ const Config = { * {Number} Amount of iterations between calls to V8 event loop. See * Manager._initLoop(), Manager.run() methods for details. */ - codeIterationsPerOnce: 100, - /** - * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef - * will be used during it's energy grabbing by system. We use this approach, - * because our CPU's are slow and organisms with big codes are very slow. But - * it's possible for organisms to go outside the limit by inventing new - * effective mechanisms of energy obtaining. - */ - codeMaxSize: 300 + codeIterationsPerOnce: 100 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 576990a..3606344 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -165,7 +165,8 @@ class Organism extends Observer { mutationProbs : this._mutationProbs, mutationPeriod : this._mutationPeriod, mutationPercent : this._mutationPercent, - mem : this.mem.slice() + mem : this.mem.slice(), + dir : this._dir }; return JSON.stringify(json); @@ -193,6 +194,7 @@ class Organism extends Observer { this._mutationPeriod = json.mutationPeriod; this._mutationPercent = json.mutationPercent; this._mem = json.mem.slice(); + this._dir = json.dir; } // TODO: describe fitness in details @@ -252,7 +254,7 @@ class Organism extends Observer { } _updateClone() { - if (this._iterations > OConfig.orgCloneMinAge && this._energy > OConfig.orgCloneMinEnergy) {this.fire(CLONE, this)} + if (OConfig.orgCloneMinAge > 0 && OConfig.orgCloneMinEnergy > 0 && 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 0208386..1962434 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -300,10 +300,10 @@ class Organisms extends Configurable { // to clone them. // if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs) { - //const randOrg = this._randOrg(); - //const rnd = Math.random(); - //if (randOrg !== org && (rnd >= (randOrg.energy / randOrg.vm.size) / this._maxEnergy || rnd <= randOrg.iterations / OConfig.orgAlivePeriod)) {randOrg.destroy()} - this._killInTour(); + const randOrg = this._randOrg(); + const rnd = Math.random(); + if (randOrg !== org && rnd <= randOrg.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} + //this._killInTour(); } if (this.organisms.length < OConfig.orgMaxOrgs && org.vm !== null) {this._clone(org)} } @@ -336,7 +336,7 @@ class Organisms extends Configurable { _updateRandomOrgs(counter) { 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} + if (!vm) {return false} const size = Helper.rand(vm.size) + 1; const pos = Helper.rand(vm.size - size); @@ -352,8 +352,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 = this._tournament(); + let org2 = this._tournament(); if (org1 === false || org2 === false || org1.energy < 1 || org2.energy < 1) {return false} this._crossover(org1, org2); diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 334c891..033a7ca 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -11,6 +11,7 @@ const EVENTS = require('./../../../../../src/share/Events').EVENTS; const OConfig = require('./../Config'); const EConfig = require('./../../energy/Config'); const Operators = require('./../../../../vm/Operators'); +const Objects = require('./../../objects/Objects'); const Organism = require('./../../../plugins/organisms/Organism').Organism; const Num = require('./../../../../vm/Num'); const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; @@ -222,20 +223,23 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function eat(line, num, org) { - const eat = this.vars[${v0}]; + let eat = this.vars[${v0}]; if (eat <= 0) {return ++line} - let x; - let y; + let x; + let y; [x, y] = NORMALIZE_NO_DIR(org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); const victim = this._positions[x][y]; if (victim < 0) {return ++line} // World object found. We can't eat objects if (victim === 0) { // Energy found - org.energy += this._world.grabDot(x, y, eat); - this._obs.fire(EVENTS.EAT_ENERGY, eat); + if ((eat = this._world.grabDot(x, y, eat)) > 0 && org.energy + eat <= OConfig.orgMaxEnergy) { + org.energy += eat; + this._obs.fire(EVENTS.EAT_ENERGY, eat); + } return ++line; } if (victim.energy <= eat) { // Organism found + if (org.energy + victim.energy > OConfig.orgMaxEnergy) {return ++line} this._obs.fire(EVENTS.KILL_EAT, victim); org.energy += victim.energy; // @@ -248,6 +252,7 @@ class OperatorsDos extends Operators { return ++line; } + if (org.energy + eat > OConfig.orgMaxEnergy) {return ++line} this._obs.fire(EVENTS.EAT_ORG, victim, eat); org.energy += eat; victim.energy -= eat; @@ -321,28 +326,43 @@ class OperatorsDos extends Operators { eval(`Operators.global.fn = function energy(line, num, org) { const poses = this._positions; const world = this._world; - let oldx = -1; - let oldy = -1; - let coef = 0; - let blocks = 0; + const energy = {0:[], 1:[], 2:[], 3:[], 4:[]}; + let e = 0; + for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { - if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { - coef += -poses[x][y]; - if (blocks++ === 0) { - oldx = x; - oldy = y; - continue; + if (IN_WORLD(x, y) && poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4}) { + e = -poses[x][y]; + energy[e].push(x, y); + if (energy[e].length === 6) { + const xy = energy[e]; + + world.setDot(xy[0], xy[1], Objects.getColor(e)); + poses[xy[0]][xy[1]] = -(e+1); + world.setDot(xy[2], xy[3], 0); + poses[xy[2]][xy[3]] = 0; + world.setDot(xy[4], xy[5], 0); + poses[xy[4]][xy[5]] = 0; + return ++line; } - world.setDot(x, y, 0); - poses[x][y] = 0; } } } - if (blocks > 1) { - org.energy += (coef * ${energy}); - world.setDot(oldx, oldy, 0); - poses[oldx][oldy] = 0; + + for (let e = 0; e < 5; e++) { + if (energy[e].length === 4) { + const xy = energy[e]; + const eat = (2**e) * EConfig.energyAmount; + + if (org.energy + eat <= OConfig.orgMaxEnergy) { + org.energy += eat; + world.setDot(xy[0], xy[1], 0); + poses[xy[0]][xy[1]] = 0; + world.setDot(xy[2], xy[3], 0); + poses[xy[2]][xy[3]] = 0; + } + return ++line; + } } return ++line; }`); @@ -373,7 +393,7 @@ class OperatorsDos extends Operators { const world = this._world; const x = org.x + OFFSX[org.dir]; const y = org.y + OFFSY[org.dir]; - if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { + if (IN_WORLD(x, y) && poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4}) { const dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; const dx = org.x + OFFSX[dir]; const dy = org.y + OFFSY[dir]; diff --git a/client/src/manager/plugins/stones/Config.js b/client/src/manager/plugins/stones/Config.js index 5ff7cdc..624e0ba 100644 --- a/client/src/manager/plugins/stones/Config.js +++ b/client/src/manager/plugins/stones/Config.js @@ -15,7 +15,7 @@ const Config = { /** * {Number} Percent from all dots in a world until stones will be added. */ - maxPercent: .05 + maxPercent: .15 }; module.exports = Config; \ No newline at end of file diff --git a/client/src/view/Canvas.js b/client/src/view/Canvas.js index a6a9af2..bb1fec5 100644 --- a/client/src/view/Canvas.js +++ b/client/src/view/Canvas.js @@ -14,21 +14,27 @@ class Canvas { doc.body.innerHTML += ``; - this._id = id; - this._width = width; - this._height = height; - this._canvasEl = doc.querySelector('#' + id); - this._ctx = this._canvasEl.getContext('2d'); - this._imgData = this._ctx.createImageData(this._width, this._height); - this._data = this._imgData.data; - this._animate = this._onAnimate.bind(this); - this._visualize = true; - this._panZoom = null; - this._fullEl = this._createFullScreen(); + this._id = id; + this._width = width; + this._height = height; + this._canvasEl = doc.querySelector('#' + id); + this._ctx = this._canvasEl.getContext('2d'); + this._imgData = this._ctx.createImageData(this._width, this._height); + this._data = this._imgData.data; + this._animate = this._onAnimate.bind(this); + this._visualize = true; + this._panZoom = null; + this._zoomObserver = null; + this._fullEl = this._createFullScreen(); + this._xDataOffs = 0; + this._yDataOffs = 0; + this._visibleWidth = Config.worldWidth; + this._visibleHeight = Config.worldHeight; this._prepareDom(); this._initPanZoomLib(); this.clear(); + this._onFullscreen(); window.requestAnimationFrame(this._animate); } @@ -100,19 +106,21 @@ class Canvas { el.title = 'fullscreen'; // TODO: use addEventListener(). - el.onclick = () => { - this._panZoom.zoomAbs(0, 0, 1.0); - this._panZoom.moveTo(0, 0); - this._canvasEl.style.width = '100%'; - this._canvasEl.style .height = '100%'; - - }; + el.onclick = this._onFullscreen.bind(this); return el; } + _onFullscreen() { + this._panZoom.zoomAbs(0, 0, 1.0); + this._panZoom.moveTo(0, 0); + this._canvasEl.style.width = '100%'; + this._canvasEl.style .height = '100%'; + } + _onAnimate() { - this._ctx.putImageData(this._imgData, 0, 0); + this._ctx.putImageData(this._imgData, 0, 0, this._xDataOffs, this._yDataOffs, this._visibleWidth, this._visibleHeight); + //this._ctx.putImageData(this._imgData, 0, 0); if (this._visualize === true) { window.requestAnimationFrame(this._animate); @@ -141,6 +149,16 @@ class Canvas { // This style hides scroll bars on full screen 2d canvas // document.querySelector('html').style.overflow = 'hidden'; + // + // Adds listener to change of canvas transform matrix. We need it + // to handle zooming of the canvas + // + this._zoomObserver = new MutationObserver(this._onZoom.bind(this)); + this._zoomObserver.observe(this._canvasEl, { + attributes : true, + childList : false, + attributeFilter: ['style'] + }); } /** @@ -156,6 +174,30 @@ class Canvas { }); this._panZoom.zoomAbs(0, 0, 1.0); } + + /** + * Is called on canvas zoom/move change + */ + _onZoom() { + const transform = window.getComputedStyle(this._canvasEl, null).getPropertyValue('transform'); + if (transform === 'none') {return} + const matrix = transform.split('(')[1].split(')')[0].split(','); + const dx = +matrix[4]; + const dy = +matrix[5]; + const coef = +matrix[0]; + const windowWidth = window.innerWidth; + const windowHeight = window.innerHeight; + const viewWidth = windowWidth * coef; + const viewHeight = windowHeight * coef; + const xCoef = Config.worldWidth / windowWidth; + const yCoef = Config.worldHeight / windowHeight; + + this._xDataOffs = (dx < 0 ? (coef > 1 ? -dx / coef : -dx * coef) : 0) * xCoef; + this._yDataOffs = (dy < 0 ? (coef > 1 ? -dy / coef : -dy * coef) : 0) * yCoef; + + this._visibleWidth = (viewWidth + dx > windowWidth ? (coef > 1 ? (windowWidth - (dx > 0 ? dx : 0)) / coef : (windowWidth - (dx > 0 ? dx : 0)) * coef) : windowWidth) * xCoef; + this._visibleHeight = (viewHeight + dy > windowHeight ? (coef > 1 ? (windowHeight - (dy > 0 ? dy : 0)) / coef : (windowHeight - (dy > 0 ? dy : 0)) * coef) : windowWidth) * yCoef; + } } module.exports = Canvas; \ No newline at end of file diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index b629add..850deed 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -110,7 +110,7 @@ class VM extends Observer { // // Every operator has it's own weight // - org.energy -= weights[op]; + org.vm && (org.energy -= (weights[op] * org.vm.size)); // // We reach the end of the script and have to run it from the beginning // From 4406915a1473efd94a68e19485c48b6052c74736 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 25 Apr 2018 23:26:26 +0300 Subject: [PATCH 15/88] added an ability to manage many populations (orgPopulations config) #34 added groups to Dots class --- client/src/manager/plugins/energy/Config.js | 17 +++++++-- .../src/manager/plugins/organisms/Config.js | 24 +++++++----- .../src/manager/plugins/organisms/Organism.js | 13 +++++-- .../manager/plugins/organisms/Organisms.js | 37 +++++++++++++++---- .../manager/plugins/organisms/dos/Organism.js | 5 ++- .../plugins/organisms/dos/Organisms.js | 21 ++++++++++- client/src/manager/plugins/stones/Config.js | 10 ++++- client/src/share/Config.js | 8 ++-- client/src/share/Dots.js | 9 ++++- client/src/view/Canvas.js | 5 ++- 10 files changed, 113 insertions(+), 36 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 4a4daab..9146085 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -8,7 +8,7 @@ const Config = { * {Number} An amount of iteration, after which we have to check world energy * percent. May be 0 if you want to disable energy generation */ - checkPeriod: 5000, + checkPeriod: 3000, /** * {Number} size of one clever energy block in dots */ @@ -22,19 +22,28 @@ const Config = { * {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 * be less then minPercent. These two configs create cyclical - * energy adding to the world. + * energy adding to the world. Energy <= orgsAmount * orgMaxEnergy. Formula: + * (orgMaxOrgs * orgCloneMinEnergy) / (worldWidth * worldHeight * energyAmount) */ - maxPercent: .3,//.0107, + maxPercent: .006028, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .005, + minPercent: .004, /** * {Number} Amount of energy in one dot */ energyAmount: 1000, + /** + * {Array|null} In case of array you may set sequence of four values: x,y,w,h. + * They means x,y coordinates, width, height of places with high energy concentration. + * Example: assume, that resolution 1920, 1080. [1920 / 2, 1080 / 2, 1920, 1080]. In this + * example all the screen will be filled by energy. As many values by four, you set as + * many places with energy will be created. In case of null, grouping will be disabled. + */ + groups: null //[1920 / 2, 1080, 500, 500 1920 + 1920 / 2, 1080, 500, 500] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 8f5f0bb..944def4 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -15,13 +15,19 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .001, .001, .001, .001, .001, // var, const, if, loop, operator, - .0001, .0001, .0001, .0001, // func, funcCall, return, bracket - .001, .001, // toMem, fromMem, - .00001, .1, .001, .001, .001, // lookAt, step, dir, myX, myY, - .01, .0001, .001, .0001, // eat, put, energy, pick - .001, .00001, .00001, .0001, .001 // rand, say, listen, check, myEnergy + .0001, .0001, .0001, .0001, .0001, // var, const, if, loop, operator, + .00001, .00001, .00001, .00001, // func, funcCall, return, bracket + .0001, .0001, // toMem, fromMem, + .000001, .01, .0001, .0001, .0001, // lookAt, step, dir, myX, myY, + .01, .00001, .0001, .00001, // eat, put, energy, pick + .0001, .000001, .000001, .00001, .0001 // rand, say, listen, check, myEnergy ], + /** + * {Number} Amount of populations in a world. This parameter affects maximum + * amount of organisms within one population. Size of sub population is equal + * to orgMaxOrgs / orgPopulations. + */ + orgPopulations: 2, /** * {Array} Probabilities which used, when mutator decides what to do: * add, change, delete code line inside the vm; change amount of @@ -104,7 +110,7 @@ const Config = { /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: 100000, + orgMaxEnergy: 100000000, /** * {Number} Amount of energy for first organisms. They are like Adam and * Eve. It means that these empty (without vm) organism were created @@ -136,11 +142,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 200, + orgMaxOrgs: 500, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 200, + orgStartAmount: 500, /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 3606344..76a45c8 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -75,14 +75,15 @@ class Organism extends Observer { * @param {Object} item Reference to the Queue item, where * this organism is located * @param {Function} operatorCls Class of operators + * @param {Number} population Index of population this organism is belong to * @param {Organism} parent Parent organism if cloning is needed */ - constructor(id, x, y, item, operatorCls, parent = null) { + constructor(id, x, y, item, operatorCls, population, parent = null) { super(EVENT_AMOUNT); this._operatorCls = operatorCls; - if (parent === null) {this._create()} + if (parent === null) {this._create(population)} else {this._clone(parent)} this._id = id; this._x = x; @@ -109,6 +110,7 @@ class Organism extends Observer { get color() {return this._color} get mem() {return this._mem} get msg() {return this._msg} + get population() {return this._population} set x(newX) {this._x = newX} set y(newY) {this._y = newY} @@ -124,6 +126,7 @@ class Organism extends Observer { set changes(c) {this._changes = c} set dir(d) {this._dir = d} set msg(m) {this._msg = m} + set population(p) {this._population = p} /** * Runs one code iteration (amount of lines set in Config.codeYieldPeriod) and returns @@ -167,6 +170,7 @@ class Organism extends Observer { mutationPercent : this._mutationPercent, mem : this.mem.slice(), dir : this._dir + // population should not be serialized }; return JSON.stringify(json); @@ -195,6 +199,7 @@ class Organism extends Observer { this._mutationPercent = json.mutationPercent; this._mem = json.mem.slice(); this._dir = json.dir; + // population should not be de-serialized } // TODO: describe fitness in details @@ -223,7 +228,7 @@ class Organism extends Observer { super.destroy(); } - _create() { + _create(population) { this.vm = new VM(this, this._operatorCls, OConfig.orgOperatorWeights); this._energy = OConfig.orgStartEnergy; this._startEnergy = OConfig.orgStartEnergy; @@ -233,6 +238,7 @@ class Organism extends Observer { this._mutationPercent = OConfig.orgRainMutationPercent; this._mem = new Array(Math.pow(2, OConfig.orgMemBits)); this._dir = Helper.rand(OFFSX.length); + this._population = population; _fill(this._mem, 0); } @@ -247,6 +253,7 @@ class Organism extends Observer { this._mutationPercent = parent.mutationPercent; this._mem = parent.mem.slice(); this._dir = parent.dir; + this._population = parent.population; } _updateColor() { diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 1962434..2a7b23d 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -68,6 +68,7 @@ class Organisms extends Configurable { this.world = manager.world; this._mutator = new Mutator(manager, this); + this._populations = new Array(OConfig.orgPopulations); this._onIterationCb = this._onIteration.bind(this); this._onLoopCb = this._onLoop.bind(this); this._onConfigChange = this._onConfigChange.bind(this); @@ -108,6 +109,7 @@ class Organisms extends Configurable { reset() { this._orgId = 0; + this._populations.fill(0); } move(x1, y1, x2, y2, org) { @@ -126,12 +128,13 @@ class Organisms extends Configurable { return true; } - createOrg(x, y, parent = null) { + createOrg(x, y, population, parent = null) { if (x === -1) {return false} const orgs = this.organisms; - let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, parent); + let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, population, parent); orgs.add(org); + this._populations[population]++; this.addOrgHandlers(org); this.world.setDot(x, y, org.color); this.positions[x][y] = org; @@ -213,7 +216,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} + if (x === -1 || this.createOrg(x, y, org.population, org) === false) {return false} let child = this.organisms.last(); if (!child) {return false} @@ -237,11 +240,20 @@ class Organisms extends Configurable { } _createPopulation() { - const world = this.world; + const world = this.world; + const populationSize = Math.floor(OConfig.orgMaxOrgs / OConfig.orgPopulations); + let population = 0; + let orgs = 0; this.reset(); for (let i = 0, len = OConfig.orgStartAmount; i < len; i++) { - this.createOrg(...world.getFreePos()); + const pos = world.getFreePos(); + this.createOrg(pos[0], pos[1], population); + if (++orgs >= populationSize) { + this._populations[population] = orgs; + orgs = 0; + population++; + } } Console.info('Population has created'); } @@ -266,6 +278,16 @@ class Organisms extends Configurable { } _onDestroyOrg(org) { + if (--this._populations[org.population] < 1) { + const orgs = this.organisms; + for (let i = 0, len = orgs.size; i < len; i++) { + const o = orgs.get(i); + if (o) { + o.population = org.population; + break; + } + } + } this.organisms.del(org.item); this.world.setDot(org.x, org.y, 0); this.positions[org.x][org.y] = 0; @@ -288,6 +310,7 @@ class Organisms extends Configurable { //if (orgAmount >= maxOrgs && (OConfig.orgKillOnClone || Math.random() <= (org.energy / org.vm.size) / this._maxEnergy)) {this._randOrg().destroy()} // if (this.organisms.length >= OConfig.orgMaxOrgs && Math.random() <= ((org.energy / 10000000000000) * (org.iterations / OConfig.orgAlivePeriod))) { // this._randOrg().destroy(); + // this._randOrg().destroy(); // } //if (this.organisms.length < maxOrgs) {this._clone(org)} //if (this.organisms.length >= maxOrgs && Math.random() <= (org.energy / org.vm.size) / this._maxEnergy) {this._randOrg().destroy()} @@ -300,12 +323,12 @@ class Organisms extends Configurable { // to clone them. // if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs) { - const randOrg = this._randOrg(); const rnd = Math.random(); + const randOrg = this._randOrg(); if (randOrg !== org && rnd <= randOrg.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} //this._killInTour(); } - if (this.organisms.length < OConfig.orgMaxOrgs && org.vm !== null) {this._clone(org)} + if (this._populations[org.population] < Math.floor(OConfig.orgMaxOrgs / OConfig.orgPopulations) && org.vm !== null) {this._clone(org)} } _killInTour() { diff --git a/client/src/manager/plugins/organisms/dos/Organism.js b/client/src/manager/plugins/organisms/dos/Organism.js index 9c395a4..1d0613f 100644 --- a/client/src/manager/plugins/organisms/dos/Organism.js +++ b/client/src/manager/plugins/organisms/dos/Organism.js @@ -16,10 +16,11 @@ class OrganismDos extends Organism { * @param {Number} y Unique Y coordinate * @param {Object} item Reference to the item index, where * this organism is located + * @param {Number} population Index of population this organism is belong to * @param {Organism} parent Parent organism if cloning is needed */ - constructor(id, x, y, item, parent = null) { - super(id, x, y, item, Operators, parent); + constructor(id, x, y, item, population, parent = null) { + super(id, x, y, item, Operators, population, parent); } onRun() { diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 3b7747e..4347328 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -155,8 +155,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.length < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent)) { - const item = this.createOrg(x, y); + const population = this._getPopulation(); + + if (ret.ret = this.world.isFree(x, y) && this.organisms.length < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent) && population !== null) { + const item = this.createOrg(x, y, population); if (item === false) {return} const org = item.val; org.unserialize(orgJson); @@ -171,6 +173,21 @@ class Organisms extends BaseOrganisms { org.energy -= energy; } } + + /** + * Returns population index, where at least one available free place exists + * @returns {Number|null} + */ + _getPopulation() { + const maxOrgs = Math.floor(OConfig.orgMaxOrgs / OConfig.orgPopulations); + const populations = this._populations; + + for (let i = 0, len = OConfig.orgPopulations; i < len; i++) { + if (populations[i] < maxOrgs) {return i} + } + + return null; + } } module.exports = Organisms; \ No newline at end of file diff --git a/client/src/manager/plugins/stones/Config.js b/client/src/manager/plugins/stones/Config.js index 624e0ba..b6b7023 100644 --- a/client/src/manager/plugins/stones/Config.js +++ b/client/src/manager/plugins/stones/Config.js @@ -15,7 +15,15 @@ const Config = { /** * {Number} Percent from all dots in a world until stones will be added. */ - maxPercent: .15 + maxPercent: .03, + /** + * {Array|null} In case of array you may set sequence of four values: x,y,w,h. + * They means x,y coordinates, width, height of places with high stones concentration. + * Example: assume, that resolution 1920, 1080. [1920 / 2, 1080 / 2, 1920, 1080]. In this + * example all the screen will be filled by stones. As many values by four, you set as + * many places with stones will be created. In case of null, grouping will be disabled. + */ + groups: [2880, 1080, 1920, 1080 * 2] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 741d332..7519271 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -40,7 +40,7 @@ ClientConfig.init({ 'client/Client', 'energy/Energy', 'stones/Stones', - 'objects/Objects', + //'objects/Objects', 'status/console/Console', IS_NODE_JS ? '' : 'status/charts/Charts', 'ips/Ips', @@ -54,11 +54,11 @@ ClientConfig.init({ /** * {Number} World width */ - worldWidth: 1920 / 4, + worldWidth: 1920 * 2, /** * {Number} World height */ - worldHeight: 1080 / 4, + 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 @@ -67,7 +67,7 @@ ClientConfig.init({ * coordinate (height). It actual only for one instance mode (no distributed * calculations). */ - worldCyclical: true, + worldCyclical: false, /** * {Number} Speed coefficient. Between 0..1. 1 - max speed, 0 - min. */ diff --git a/client/src/share/Dots.js b/client/src/share/Dots.js index 446cfa1..24c0d32 100644 --- a/client/src/share/Dots.js +++ b/client/src/share/Dots.js @@ -101,8 +101,13 @@ class Dots extends Configurable { const blockSize = this._config.blockSize; const setCb = this._cfg.setCb; const colorCb = this._cfg.colorCb; - let x = Helper.rand(width); - let y = Helper.rand(height); + const groups = this._config.groups; + const rand = Helper.rand; + const groupAmount = groups ? groups.length : 0; + const xCoord = rand(groupAmount / 4) * 4; + const yCoord = rand(groupAmount / 4) * 4; + let x = groups ? groups[xCoord] - rand(groups[xCoord + 2] / 2) + rand(groups[xCoord + 2] / 2) : rand(width); + let y = groups ? groups[yCoord + 1] - rand(groups[yCoord + 3] / 2) + rand(groups[yCoord + 3] / 2) : rand(height); for (let i = 0; i < blockSize; i++) { x = x + Helper.rand(3) - 1; diff --git a/client/src/view/Canvas.js b/client/src/view/Canvas.js index bb1fec5..d9cc425 100644 --- a/client/src/view/Canvas.js +++ b/client/src/view/Canvas.js @@ -120,7 +120,6 @@ class Canvas { _onAnimate() { this._ctx.putImageData(this._imgData, 0, 0, this._xDataOffs, this._yDataOffs, this._visibleWidth, this._visibleHeight); - //this._ctx.putImageData(this._imgData, 0, 0); if (this._visualize === true) { window.requestAnimationFrame(this._animate); @@ -176,7 +175,9 @@ class Canvas { } /** - * Is called on canvas zoom/move change + * Is called on canvas zoom/move change. This method improves rendering + * speed of big canvases. It copies only visible part of the canvas from + * memory (see this._imgData). */ _onZoom() { const transform = window.getComputedStyle(this._canvasEl, null).getPropertyValue('transform'); From b34a2f96802278bce1bd16452db867790e2b9fb0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 27 Apr 2018 14:01:53 +0300 Subject: [PATCH 16/88] added poison command #135 added ability to pick energy removed population related code new starting energy/rocks configuration --- client/src/manager/plugins/energy/Config.js | 6 +- .../src/manager/plugins/organisms/Config.js | 32 +++++---- .../src/manager/plugins/organisms/Organism.js | 16 ++--- .../manager/plugins/organisms/Organisms.js | 64 +++++++---------- .../plugins/organisms/dos/Operators.js | 70 ++++++++++++++----- .../manager/plugins/organisms/dos/Organism.js | 5 +- .../plugins/organisms/dos/Organisms.js | 27 ++----- client/src/manager/plugins/stones/Config.js | 2 +- client/src/share/Config.js | 4 +- common/src/FastArray.js | 9 ++- common/src/FastArraySpec.js | 48 +++++++++++++ 11 files changed, 167 insertions(+), 116 deletions(-) create mode 100644 common/src/FastArraySpec.js diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 9146085..1f4c327 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -25,13 +25,13 @@ const Config = { * energy adding to the world. Energy <= orgsAmount * orgMaxEnergy. Formula: * (orgMaxOrgs * orgCloneMinEnergy) / (worldWidth * worldHeight * energyAmount) */ - maxPercent: .006028, + maxPercent: .0007535, /** * {Number} Opposite to maxPercent. Sets minimum percent from * all energy in a world after which clever energy will turn on (be added to the * world again). */ - minPercent: .004, + minPercent: .0004, /** * {Number} Amount of energy in one dot */ @@ -43,7 +43,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: null //[1920 / 2, 1080, 500, 500 1920 + 1920 / 2, 1080, 500, 500] + groups: [3000, 1080 * 2, 2000, 500, 1920 * 2.5, 1080 * 2, 2000, 500] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 944def4..41d9bf0 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -19,15 +19,9 @@ const Config = { .00001, .00001, .00001, .00001, // func, funcCall, return, bracket .0001, .0001, // toMem, fromMem, .000001, .01, .0001, .0001, .0001, // lookAt, step, dir, myX, myY, - .01, .00001, .0001, .00001, // eat, put, energy, pick - .0001, .000001, .000001, .00001, .0001 // rand, say, listen, check, myEnergy + .01, .00001, .0001, .00001, .0001, // eat, put, energy, pick, poison, + .0001, .000001, .000001, .00001, .0001, // rand, say, listen, check, myEnergy ], - /** - * {Number} Amount of populations in a world. This parameter affects maximum - * amount of organisms within one population. Size of sub population is equal - * to orgMaxOrgs / orgPopulations. - */ - orgPopulations: 2, /** * {Array} Probabilities which used, when mutator decides what to do: * add, change, delete code line inside the vm; change amount of @@ -58,7 +52,7 @@ const Config = { * {Number} Minimum age for cloning. Before that, cloning is impossible. It should * be less then orgAlivePeriod config */ - orgCloneMinAge: 100, + orgCloneMinAge: 1000, /** * {Number} Minimum energy for cloning */ @@ -69,7 +63,7 @@ const Config = { * 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 @@ -96,27 +90,35 @@ 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: 0, + orgCrossoverPeriod: 1100, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 0, + orgRandomOrgPeriod: 1000, /** * {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: 30000, /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: 100000000, + orgMaxEnergy: 100000, /** * {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: 100000, + /** + * {Number} Amount of energy, that grabs from organism in case of eating poison + */ + orgPoisonValue: 10000, + /** + * {Number} Color index of poison dot + */ + orgPoisonColor: 6645, /** * {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 76a45c8..0b78742 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -12,6 +12,7 @@ const OConfig = require('./../../../manager/plugins/organisms/Config'); const EVENT_AMOUNT = require('./../../../share/Events').EVENT_AMOUNT; const VM = require('./../../../vm/VM'); const OFFSX = require('./../../../../../common/src/Directions').OFFSX; +const OFFSY = require('./../../../../../common/src/Directions').OFFSY; const DESTROY = 0; const CLONE = 1; @@ -75,15 +76,14 @@ class Organism extends Observer { * @param {Object} item Reference to the Queue item, where * this organism is located * @param {Function} operatorCls Class of operators - * @param {Number} population Index of population this organism is belong to * @param {Organism} parent Parent organism if cloning is needed */ - constructor(id, x, y, item, operatorCls, population, parent = null) { + constructor(id, x, y, item, operatorCls, parent = null) { super(EVENT_AMOUNT); this._operatorCls = operatorCls; - if (parent === null) {this._create(population)} + if (parent === null) {this._create()} else {this._clone(parent)} this._id = id; this._x = x; @@ -110,7 +110,8 @@ class Organism extends Observer { get color() {return this._color} get mem() {return this._mem} get msg() {return this._msg} - get population() {return this._population} + get dirX() {return this._x + OFFSX[this._dir]} + get dirY() {return this._y + OFFSY[this._dir]} set x(newX) {this._x = newX} set y(newY) {this._y = newY} @@ -126,7 +127,6 @@ class Organism extends Observer { set changes(c) {this._changes = c} set dir(d) {this._dir = d} set msg(m) {this._msg = m} - set population(p) {this._population = p} /** * Runs one code iteration (amount of lines set in Config.codeYieldPeriod) and returns @@ -170,7 +170,6 @@ class Organism extends Observer { mutationPercent : this._mutationPercent, mem : this.mem.slice(), dir : this._dir - // population should not be serialized }; return JSON.stringify(json); @@ -199,7 +198,6 @@ class Organism extends Observer { this._mutationPercent = json.mutationPercent; this._mem = json.mem.slice(); this._dir = json.dir; - // population should not be de-serialized } // TODO: describe fitness in details @@ -228,7 +226,7 @@ class Organism extends Observer { super.destroy(); } - _create(population) { + _create() { this.vm = new VM(this, this._operatorCls, OConfig.orgOperatorWeights); this._energy = OConfig.orgStartEnergy; this._startEnergy = OConfig.orgStartEnergy; @@ -238,7 +236,6 @@ class Organism extends Observer { this._mutationPercent = OConfig.orgRainMutationPercent; this._mem = new Array(Math.pow(2, OConfig.orgMemBits)); this._dir = Helper.rand(OFFSX.length); - this._population = population; _fill(this._mem, 0); } @@ -253,7 +250,6 @@ class Organism extends Observer { this._mutationPercent = parent.mutationPercent; this._mem = parent.mem.slice(); this._dir = parent.dir; - this._population = parent.population; } _updateColor() { diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 2a7b23d..fd6e86f 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -52,12 +52,6 @@ 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)'], @@ -68,7 +62,8 @@ class Organisms extends Configurable { this.world = manager.world; this._mutator = new Mutator(manager, this); - this._populations = new Array(OConfig.orgPopulations); + this._oldOrg = null; + this._curOldOrg = null; this._onIterationCb = this._onIteration.bind(this); this._onLoopCb = this._onLoop.bind(this); this._onConfigChange = this._onConfigChange.bind(this); @@ -99,6 +94,19 @@ class Organisms extends Configurable { super.destroy(); } + /** + * Is called at the end of run() method + * @param {Organism} org Current organism + * @param {Number} i Current organism index/id + */ + onOrganism(org, i) { + if (i === 0) { + this._oldOrg = this._curOldOrg; + this._curOldOrg = org; + } + if (this._curOldOrg.iterations < org.iterations) {this._curOldOrg = org} + } + addOrgHandlers(org) { org.on(ORG_EVENTS.DESTROY, this._onDestroyOrg.bind(this)); org.on(ORG_EVENTS.KILL_NO_ENERGY, this._onKillNoEnergyOrg.bind(this)); @@ -109,7 +117,6 @@ class Organisms extends Configurable { reset() { this._orgId = 0; - this._populations.fill(0); } move(x1, y1, x2, y2, org) { @@ -128,13 +135,12 @@ class Organisms extends Configurable { return true; } - createOrg(x, y, population, parent = null) { + createOrg(x, y, parent = null) { if (x === -1) {return false} const orgs = this.organisms; - let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, population, parent); + let org = this.createEmptyOrg(++this._orgId + '', x, y, orgs.freeIndex, parent); orgs.add(org); - this._populations[population]++; this.addOrgHandlers(org); this.world.setDot(x, y, org.color); this.positions[x][y] = org; @@ -167,7 +173,7 @@ class Organisms extends Configurable { for (let i = 0, len = orgs.size; i < len; i++) { if ((org = orgs.get(i)) === null) {continue} org.run(); - this.onOrganism(org); + this.onOrganism(org, i); } this._updateTournament(counter); @@ -216,7 +222,7 @@ class Organisms extends Configurable { let y; [x, y] = this.world.getNearFreePos(org.x, org.y); - if (x === -1 || this.createOrg(x, y, org.population, org) === false) {return false} + if (x === -1 || this.createOrg(x, y, org) === false) {return false} let child = this.organisms.last(); if (!child) {return false} @@ -240,20 +246,11 @@ class Organisms extends Configurable { } _createPopulation() { - const world = this.world; - const populationSize = Math.floor(OConfig.orgMaxOrgs / OConfig.orgPopulations); - let population = 0; - let orgs = 0; + const world = this.world; this.reset(); for (let i = 0, len = OConfig.orgStartAmount; i < len; i++) { - const pos = world.getFreePos(); - this.createOrg(pos[0], pos[1], population); - if (++orgs >= populationSize) { - this._populations[population] = orgs; - orgs = 0; - population++; - } + this.createOrg(...world.getFreePos()); } Console.info('Population has created'); } @@ -278,16 +275,6 @@ class Organisms extends Configurable { } _onDestroyOrg(org) { - if (--this._populations[org.population] < 1) { - const orgs = this.organisms; - for (let i = 0, len = orgs.size; i < len; i++) { - const o = orgs.get(i); - if (o) { - o.population = org.population; - break; - } - } - } this.organisms.del(org.item); this.world.setDot(org.x, org.y, 0); this.positions[org.x][org.y] = 0; @@ -322,13 +309,12 @@ class Organisms extends Configurable { // organisms before cloning. They should kill each other to have a possibility // to clone them. // - if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs) { - const rnd = Math.random(); - const randOrg = this._randOrg(); - if (randOrg !== org && rnd <= randOrg.iterations / OConfig.orgAlivePeriod) {randOrg.destroy()} + if (OConfig.orgKillOnClone && this.organisms.length >= OConfig.orgMaxOrgs && this._oldOrg) { + this._oldOrg.destroy(); + this._oldOrg = null; //this._killInTour(); } - if (this._populations[org.population] < Math.floor(OConfig.orgMaxOrgs / OConfig.orgPopulations) && org.vm !== null) {this._clone(org)} + if (this.organisms.length < OConfig.orgMaxOrgs && org.vm !== null) {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 033a7ca..818551a 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -35,7 +35,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.codeBitsPerOperator; - this.OPERATOR_AMOUNT = 25; + this.OPERATOR_AMOUNT = 26; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -57,6 +57,7 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - bitsPerOp); this._compileLookAt(); // 11 this._compileStep(); // 12 @@ -72,6 +73,7 @@ class OperatorsDos extends Operators { this._compileListen(); // 22 this._compileCheck(); // 23 this._compileMyEnergy(); // 24 + this._compilePoison(); // 25 } /** @@ -119,7 +121,7 @@ class OperatorsDos extends Operators { */ static _compileStep() { eval(`OperatorsDos.global.fn = function step(line, num, org) { - this._obs.fire(${EVENTS.STEP}, org, org.x, org.y, org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); + this._obs.fire(${EVENTS.STEP}, org, org.x, org.y, org.dirX, org.dirY); return ++line; }`); this._compiledOperators[this._toHexNum(`${'101100'}`)] = this.global.fn; @@ -227,18 +229,24 @@ class OperatorsDos extends Operators { if (eat <= 0) {return ++line} let x; let y; - [x, y] = NORMALIZE_NO_DIR(org.x + OFFSX[org.dir], org.y + OFFSY[org.dir]); + [x, y] = NORMALIZE_NO_DIR(org.dirX, org.dirY); const victim = this._positions[x][y]; - if (victim < 0) {return ++line} // World object found. We can't eat objects - if (victim === 0) { // Energy found + if (victim === OBJECT_TYPES.POISON) { // Poison found + this._positions[x][y] = 0; + this._world.setDot(x, y, 0); + org.destroy(); + return ++line; + } + if (victim < 0) {return ++line} // World object found. We can't eat objects + if (victim === 0) { // Energy found if ((eat = this._world.grabDot(x, y, eat)) > 0 && org.energy + eat <= OConfig.orgMaxEnergy) { org.energy += eat; this._obs.fire(EVENTS.EAT_ENERGY, eat); } return ++line; } - if (victim.energy <= eat) { // Organism found + if (victim.energy <= eat) { // Organism found if (org.energy + victim.energy > OConfig.orgMaxEnergy) {return ++line} this._obs.fire(EVENTS.KILL_EAT, victim); org.energy += victim.energy; @@ -285,10 +293,10 @@ class OperatorsDos extends Operators { eval(`Operators.global.fn = function put(line, num, org) { let put = this.vars[${v0}]; if (put <= 0) {return ++line} - let x = org.x + OFFSX[org.dir]; - let y = org.y + OFFSY[org.dir]; + let x = org.dirX; + let y = org.dirY; if (!IN_WORLD(x, y)) {return ++line} - if (this._world.data[x][y] > 0) {return ++line} + if (this._world.data[x][y] !== 0) {return ++line} if (org.energy <= put) { put = org.energy; this._world.setDot(x, y, put); @@ -321,7 +329,6 @@ class OperatorsDos extends Operators { static _compileEnergy() { const ops = this._compiledOperators; const h = this._toHexNum; - const energy = Organism.getColor(EConfig.colorIndex); eval(`Operators.global.fn = function energy(line, num, org) { const poses = this._positions; @@ -331,7 +338,7 @@ class OperatorsDos extends Operators { for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { - if (IN_WORLD(x, y) && poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4}) { + if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { e = -poses[x][y]; energy[e].push(x, y); if (energy[e].length === 6) { @@ -391,9 +398,9 @@ class OperatorsDos extends Operators { eval(`Operators.global.fn = function pick(line, num, org) { const poses = this._positions; const world = this._world; - const x = org.x + OFFSX[org.dir]; - const y = org.y + OFFSY[org.dir]; - if (IN_WORLD(x, y) && poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4}) { + const x = org.dirX; + const y = org.dirY; + if (IN_WORLD(x, y) && (poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 || poses[x][y] === 0 && world.data[x][y] > 0)) { const dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; const dx = org.x + OFFSX[dir]; const dy = org.y + OFFSY[dir]; @@ -457,8 +464,8 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function say(line, num, org) { - let x = org.x + OFFSX[org.dir]; - let y = org.y + OFFSY[org.dir]; + let x = org.dirX; + let y = org.dirY; IN_WORLD(x, y) && !(this._positions[x][y] <= 0) && (this._positions[x][y].msg = this.vars[${v0}]); return ++line; }`); @@ -511,8 +518,8 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function check(line, num, org) { - const x = org.x + OFFSX[org.dir]; - const y = org.y + OFFSY[org.dir]; + const x = org.dirX; + const y = org.dirY; if (!IN_WORLD(x, y)) {return ++line} if (this._positions[x][y] < 0) { @@ -555,6 +562,33 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'poison' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Poison direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 + * number: 111001... + * string: poison + */ + static _compilePoison() { + const ops = this._compiledOperators; + const h = this._toHexNum; + + eval(`Operators.global.fn = function poison(line, num, org) { + let x = org.dirX; + let y = org.dirY; + if (!IN_WORLD(x, y) || this._world.data[x][y] !== 0 || org.energy <= OConfig.orgPoisonValue) {return ++line} + + this._world.setDot(x, y, Organism.getColor(OConfig.orgPoisonColor)); + this._positions[x][y] = OBJECT_TYPES.POISON; + if ((org.energy -= OConfig.orgPoisonValue) < 0) {org.destroy()} + return ++line; + }`); + ops[h(`${'111001'}`)] = this.global.fn; + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** diff --git a/client/src/manager/plugins/organisms/dos/Organism.js b/client/src/manager/plugins/organisms/dos/Organism.js index 1d0613f..9c395a4 100644 --- a/client/src/manager/plugins/organisms/dos/Organism.js +++ b/client/src/manager/plugins/organisms/dos/Organism.js @@ -16,11 +16,10 @@ class OrganismDos extends Organism { * @param {Number} y Unique Y coordinate * @param {Object} item Reference to the item index, where * this organism is located - * @param {Number} population Index of population this organism is belong to * @param {Organism} parent Parent organism if cloning is needed */ - constructor(id, x, y, item, population, parent = null) { - super(id, x, y, item, Operators, population, parent); + constructor(id, x, y, item, parent = null) { + super(id, x, y, item, Operators, parent); } onRun() { diff --git a/client/src/manager/plugins/organisms/dos/Organisms.js b/client/src/manager/plugins/organisms/dos/Organisms.js index 4347328..4b1cbbf 100644 --- a/client/src/manager/plugins/organisms/dos/Organisms.js +++ b/client/src/manager/plugins/organisms/dos/Organisms.js @@ -17,12 +17,16 @@ const OConfig = require('./../Config'); const EVENTS = require('./../../../../share/Events').EVENTS; const Helper = require('./../../../../../../common/src/Helper'); const DIR = require('./../../../../../../common/src/Directions').DIR; +const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; +// +// We have to add object types to global types storage +// +OBJECT_TYPES.POISON = -(Object.keys(OBJECT_TYPES).length + 1); /** * {Function} Is created to speed up this function call. constants are run * much faster, then Helper.normalize() */ const NORMALIZE = Helper.normalize; -const NORMALIZE_NO_DIR = Helper.normalizeNoDir; class Organisms extends BaseOrganisms { constructor(manager) { @@ -155,10 +159,8 @@ class Organisms extends BaseOrganisms { * @param {Object} ret Return object */ _onStepIn(x, y, orgJson, ret) { - const population = this._getPopulation(); - - if (ret.ret = this.world.isFree(x, y) && this.organisms.length < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent) && population !== null) { - const item = this.createOrg(x, y, population); + if (ret.ret = this.world.isFree(x, y) && this.organisms.length < (OConfig.orgMaxOrgs + OConfig.orgMaxOrgs * OConfig.orgStepOverflowPercent)) { + const item = this.createOrg(x, y); if (item === false) {return} const org = item.val; org.unserialize(orgJson); @@ -173,21 +175,6 @@ class Organisms extends BaseOrganisms { org.energy -= energy; } } - - /** - * Returns population index, where at least one available free place exists - * @returns {Number|null} - */ - _getPopulation() { - const maxOrgs = Math.floor(OConfig.orgMaxOrgs / OConfig.orgPopulations); - const populations = this._populations; - - for (let i = 0, len = OConfig.orgPopulations; i < len; i++) { - if (populations[i] < maxOrgs) {return i} - } - - return null; - } } module.exports = Organisms; \ No newline at end of file diff --git a/client/src/manager/plugins/stones/Config.js b/client/src/manager/plugins/stones/Config.js index b6b7023..55f0ef6 100644 --- a/client/src/manager/plugins/stones/Config.js +++ b/client/src/manager/plugins/stones/Config.js @@ -23,7 +23,7 @@ const Config = { * example all the screen will be filled by stones. As many values by four, you set as * many places with stones will be created. In case of null, grouping will be disabled. */ - groups: [2880, 1080, 1920, 1080 * 2] + groups: [1920 * 3, 1080 * 2, 1920 * 2, 1080 * 4] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 7519271..2b7257d 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -54,11 +54,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 diff --git a/common/src/FastArray.js b/common/src/FastArray.js index b127d20..d8445f0 100644 --- a/common/src/FastArray.js +++ b/common/src/FastArray.js @@ -1,9 +1,8 @@ /** - * 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 null to specified index. + * Implementation of fast array. This class uses fixed array size. Second that + * get() method will be called must of the time, then set() or del() or resize(). + * Resize is possible, but should be rare to keep it fast. Is used for storing + * organisms population. Removing element means setting null to specified index. * * @author flatline */ diff --git a/common/src/FastArraySpec.js b/common/src/FastArraySpec.js new file mode 100644 index 0000000..678856e --- /dev/null +++ b/common/src/FastArraySpec.js @@ -0,0 +1,48 @@ +describe('common/src/FastArray', () => { + const FastArray = require('./FastArray'); + const size = 10; + let fa; + + beforeEach(() => fa = new FastArray(size)); + afterEach (() => {fa.destroy(); fa = null}); + + it('Checking creation', () => { + expect(fa.size).toEqual(size); + expect(fa.length).toEqual(0); + expect(fa.freeIndex).toEqual(size - 1); + }); + + it('Checking destroy', () => { + const fSize = 3; + const fa1 = new FastArray(fSize); + expect(fa1.size).toEqual(fSize); + fa1.destroy(); + expect(fa1.size).toEqual(null); + }); + + it('Checking length property', () => { + fa.add({}); + expect(fa.length).toEqual(1); + fa.get(size - 1); + expect(fa.length).toEqual(1); + fa.del(size - 1); + expect(fa.length).toEqual(0); + fa.resize(size * 2); + expect(fa.length).toEqual(0); + fa.add({}); + expect(fa.length).toEqual(1); + fa.resize(size); + expect(fa.length).toEqual(0); + fa.add({}); + fa.add({}); + expect(fa.length).toEqual(2); + }); + + it('Checking size property', () => { + expect(fa.size).toEqual(size); + fa.add({}); + expect(fa.size).toEqual(size); + fa.del(size - 1); + expect(fa.size).toEqual(size); + }); +}); \ No newline at end of file From 69066ad19ad2b6fe7f23c24d207844f08fff91cc Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 2 May 2018 15:21:11 +0300 Subject: [PATCH 17/88] fixed wrong behavior in FastArray added tests for FastArray implemented minimum amount of available energy concept (beta regime) --- client/src/manager/Manager.js | 9 +- client/src/manager/ManagerSpec.js | 20 ++--- client/src/manager/plugins/energy/Config.js | 30 +++---- client/src/manager/plugins/energy/Energy.js | 27 +++++- client/src/manager/plugins/objects/Config.js | 14 ++- client/src/manager/plugins/objects/Objects.js | 3 +- .../src/manager/plugins/organisms/Config.js | 30 +++---- .../src/manager/plugins/organisms/Organism.js | 22 +---- .../manager/plugins/organisms/Organisms.js | 42 ++++++--- .../plugins/organisms/dos/Operators.js | 9 +- client/src/manager/plugins/status/Status.js | 2 +- client/src/manager/plugins/stones/Config.js | 13 +-- client/src/share/Dots.js | 51 +++++++---- common/src/FastArray.js | 48 +++++----- common/src/FastArraySpec.js | 88 ++++++++++++++++++- common/src/Helper.js | 17 ++++ tests/jasmine.json | 7 +- 17 files changed, 289 insertions(+), 143 deletions(-) diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index f3ec623..963ef0b 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -71,6 +71,7 @@ class Manager extends Observer { */ this._codeRuns = 0; + this._sharedObj = {}; this._world = new World(Config.worldWidth, Config.worldHeight); this._canvas = hasView && new Canvas(Config.worldWidth, Config.worldHeight) || null; this._visualized = true; @@ -101,6 +102,7 @@ class Manager extends Observer { }); } + get sharedObj() {return this._sharedObj} get world() {return this._world} get canvas() {return this._canvas} get clientId() {return this._clientId} @@ -152,8 +154,9 @@ class Manager extends Observer { * Is called after all iterations * @param {Number} counter Global counter as an analog of time * @param {Number} stamp UNIX time stamp + * @param {Object} sharedObj Shared manager's object */ - onLoop(counter, stamp) { + onLoop(counter, stamp, sharedObj) { this.fire(EVENTS.LOOP); } @@ -269,8 +272,8 @@ class Manager extends Observer { for (i = counter, amount = counter + amount; i < amount; i++) { this.onIteration(i, TIMER()); } - this.onLoop(this._counter = i, TIMER()); - Helper.delay((1 - Config.worldSpeed) * 60); + this.onLoop(this._counter = i, TIMER(), this._sharedObj); + Helper.delay((1 - Config.worldSpeed) * 100); this.zeroTimeout(this._onLoopCb); } diff --git a/client/src/manager/ManagerSpec.js b/client/src/manager/ManagerSpec.js index ee8fe93..ce0c8ca 100644 --- a/client/src/manager/ManagerSpec.js +++ b/client/src/manager/ManagerSpec.js @@ -399,7 +399,7 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { - org1 = man1.organisms.last(); + org1 = man1.organisms.added(); org1.vm.insertLine(); org1.vm.updateLine(0, 0b00001011000000000000000000000000); // onStepRight() } else if (man2.organisms.length === 2) { @@ -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.last(); + org1 = man1.organisms.added(); org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() man1.on(EVENTS.STEP_OUT, () => { expect(doneInc < 3).toBe(true); @@ -475,13 +475,13 @@ describe("client/src/manager/Manager", () => { man2.on(EVENTS.STEP_IN, () => { ++doneInc; expect(man1.organisms.length).toBe(1); - expect(man1.organisms.last().x).toBe(0); + expect(man1.organisms.added().x).toBe(0); }); } else if (org1 !== null && org2 !== null && doneInc === 2) { expect(man1.organisms.length).toBe(1); - expect(man1.organisms.last().x).toBe(0); + expect(man1.organisms.added().x).toBe(0); expect(man2.organisms.length).toBe(1); - expect(man2.organisms.last().x).toBe(0); + expect(man2.organisms.added().x).toBe(0); destroy(); doneInc++; } @@ -489,7 +489,7 @@ describe("client/src/manager/Manager", () => { iterated1++; }); man2.on(EVENTS.LOOP, () => { - !iterated2 && (org2 = man2.organisms.last()); + !iterated2 && (org2 = man2.organisms.added()); iterated2++; }); @@ -555,7 +555,7 @@ describe("client/src/manager/Manager", () => { man1.on(EVENTS.LOOP, () => { if (iterated1 > 0 && iterated2 > 0 && org1 === null) { expect(man2.organisms.length).toBe(1); - org1 = man1.organisms.last(); + org1 = man1.organisms.added(); org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() } else if (man2.organisms.length === 2) { destroy(); @@ -766,7 +766,7 @@ describe("client/src/manager/Manager", () => { // man1.on(EVENTS.LOOP, () => { // if (iterated1 > 0 && iterated2 > 0 && org1 === null) { // expect(man2.organisms.length).toBe(1); -// org1 = man1.organisms.last(); +// org1 = man1.organisms.added(); // org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() // man1.on(EVENTS.KILL, () => destroyFlag = true); // man1.on(EVENTS.STEP_IN, () => stepInBack = true); @@ -840,7 +840,7 @@ describe("client/src/manager/Manager", () => { // // man1.on(EVENTS.LOOP, () => { // if (iterated1 > 0 && org1 === null) { -// org1 = man1.organisms.last(); +// org1 = man1.organisms.added(); // org1.vm.code.push(0b00001011000000000000000000000000); // onStepRight() // man1.on(EVENTS.KILL, () => destroyFlag = true); // man1.on(EVENTS.STEP_IN, () => stepInBack = true); @@ -897,7 +897,7 @@ describe("client/src/manager/Manager", () => { // testQ(done, // [server, SEVENTS.RUN, () => server.run(), () => {man1.run(() => man2.run(() => man3.run(() => waitObj.done = true)))}], // [waitObj], -// [man1, EVENTS.LOOP, emp, () => man1.organisms.last().vm.code.push(0b00001011000000000000000000000000)], // onStepRight() +// [man1, EVENTS.LOOP, emp, () => man1.organisms.added().vm.code.push(0b00001011000000000000000000000000)], // onStepRight() // [man3, EVENTS.STEP_IN, emp, () => destroy()] // ); // }); diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 1f4c327..3f30fb9 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -3,7 +3,11 @@ * * @author flatline */ -const Config = { +const Helper = require('./../../../../../common/src/Helper'); + +const ENERGY_COLOR = 10000; +const COLOR = Helper.getColor; +const Config = { /** * {Number} An amount of iteration, after which we have to check world energy * percent. May be 0 if you want to disable energy generation @@ -12,30 +16,20 @@ const Config = { /** * {Number} size of one clever energy block in dots */ - blockSize: 10, + blockSize: 2, /** * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS * constant for details */ - colorIndex: 10000, - /** - * {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 - * be less then minPercent. These two configs create cyclical - * energy adding to the world. Energy <= orgsAmount * orgMaxEnergy. Formula: - * (orgMaxOrgs * orgCloneMinEnergy) / (worldWidth * worldHeight * energyAmount) - */ - maxPercent: .0007535, + colorIndex: ENERGY_COLOR, /** - * {Number} Opposite to maxPercent. Sets minimum percent from - * all energy in a world after which clever energy will turn on (be added to the - * world again). + * {Number} Maximum amount of energy dots */ - minPercent: .0004, + maxValue: .8 * COLOR(ENERGY_COLOR) * 4000, /** - * {Number} Amount of energy in one dot + * {Number} Opposite to maxValue. Minimum amount of energy dots */ - energyAmount: 1000, + minValue: .6 * COLOR(ENERGY_COLOR) * 4000, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high energy concentration. @@ -43,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [3000, 1080 * 2, 2000, 500, 1920 * 2.5, 1080 * 2, 2000, 500] + groups: [1920 * 2, 1080 * 2, 500, 500] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/energy/Energy.js b/client/src/manager/plugins/energy/Energy.js index 5866f3a..756679e 100644 --- a/client/src/manager/plugins/energy/Energy.js +++ b/client/src/manager/plugins/energy/Energy.js @@ -4,20 +4,39 @@ * @author flatline */ const Dots = require('./../../../share/Dots'); -const Config = require('./Config'); +const EConfig = require('./Config'); const EVENTS = require('./../../../share/Events').EVENTS; +const Helper = require('./../../../../../common/src/Helper'); class Energy extends Dots { constructor(manager) { - super(manager, Config, { + super(manager, EConfig, { addOnce : false, - compareCb: (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0 + compareCb: (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0, + checkMin : (val) => val + this._sharedObj.orgEnergy < this.config.minValue }); + this._color = Helper.getColor(EConfig.colorIndex); + this._energy = 0; + this._sharedObj = manager.sharedObj; } onIteration(counter) { const energy = super.onIteration(counter); - energy !== false && this.manager.fire(EVENTS.WORLD_ENERGY, energy); + if (energy !== false) { + this.manager.fire(EVENTS.WORLD_ENERGY, (energy + this._sharedObj.orgEnergy) / this._color); + this._energy = energy; + } + } + + /** + * Override of Manager.onLoop() method. Stores amount of energy in sharedObj + * @param {Number} counter Global counter. Time analog + * @param {Number} stamp Time stamp + * @param {Object} sharedObj Shared object of the manager + */ + onLoop(counter, stamp, sharedObj) { + super.onLoop(sharedObj); + sharedObj.energy = this._energy; } } diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index fa81649..ffa17f4 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -3,6 +3,8 @@ * * @author flatline */ +const Helper = require('./../../../../../common/src/Helper'); + const Config = { /** * {Number} An amount of iteration, after which we have to check world energy @@ -14,17 +16,13 @@ const Config = { */ blockSize: 10, /** - * {Number} Percent from all energy objects in a world until clever energy will - * be added. After this value energy objects will be stopped to add until it's - * amount will be less then minPercent. These two configs create cyclical - * energy objects adding to the world. + * {Number} Maximum amount of object dots */ - maxPercent: .3, + maxValue: 100 * Helper.getColor(8500 + 2 * 500), /** - * {Number} Opposite to maxPercent. Sets minimum percent from all energy objects - * in a world after which energy objects will turn on (be added to the world again). + * {Number} Opposite to maxValue. Minimum amount of object dots */ - minPercent: .1 + minValue: 50 * Helper.getColor(8500 + 2 * 500) }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js index 1b37220..ff2d4e4 100644 --- a/client/src/manager/plugins/objects/Objects.js +++ b/client/src/manager/plugins/objects/Objects.js @@ -7,7 +7,6 @@ const Dots = require('./../../../share/Dots'); const Helper = require('./../../../../../common/src/Helper'); const Config = require('./Config'); -const Organism = require('./../../plugins/organisms/Organism').Organism; const OBJECT_TYPES = require('./../../../view/World').OBJECT_TYPES; // // We have to add object types to global types storage @@ -18,7 +17,7 @@ OBJECT_TYPES.TYPE_ENERGY2 = -(Object.keys(OBJECT_TYPES).length + 1); OBJECT_TYPES.TYPE_ENERGY3 = -(Object.keys(OBJECT_TYPES).length + 1); OBJECT_TYPES.TYPE_ENERGY4 = -(Object.keys(OBJECT_TYPES).length + 1); -const GET_COLOR = (index) => Organism.getColor(8500 + (Math.abs(index) + OBJECT_TYPES.TYPE_ENERGY0) * 500); +const GET_COLOR = (index) => Helper.getColor(8500 + (Math.abs(index) + OBJECT_TYPES.TYPE_ENERGY0) * 500); const COLOR_INDEX = OBJECT_TYPES.TYPE_ENERGY0; const COLOR_RGB = GET_COLOR(COLOR_INDEX); diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 41d9bf0..28e979c 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, .0001, .0001, .0001, // var, const, if, loop, operator, - .00001, .00001, .00001, .00001, // func, funcCall, return, bracket - .0001, .0001, // toMem, fromMem, - .000001, .01, .0001, .0001, .0001, // lookAt, step, dir, myX, myY, - .01, .00001, .0001, .00001, .0001, // eat, put, energy, pick, poison, - .0001, .000001, .000001, .00001, .0001, // rand, say, listen, check, myEnergy + .01, .01, .01, .01, .01, // var, const, if, loop, operator, + .001, .001, .001, .001, // func, funcCall, return, bracket + .01, .01, // toMem, fromMem, + .0001, .1, .01, .01, .01, // lookAt, step, dir, myX, myY, + .1, .001, .01, .01, .01, // eat, put, energy, pick, poison, + .01, .0001, .0001, .001, .01 // rand, say, listen, check, myEnergy ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -56,7 +56,7 @@ const Config = { /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: 80000, + orgCloneMinEnergy: .8 * 0x6d3b4, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -90,12 +90,12 @@ 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: 1100, + orgCrossoverPeriod: 0, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 1000, + orgRandomOrgPeriod: 0, /** * {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 @@ -104,17 +104,17 @@ const Config = { /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: 100000, + orgMaxEnergy: 1 * 0x6d3b4, /** * {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: 100000, + orgStartEnergy: 1 * 0x6d3b4, /** * {Number} Amount of energy, that grabs from organism in case of eating poison */ - orgPoisonValue: 10000, + orgPoisonValue: .5 * 0x6d3b4, /** * {Number} Color index of poison dot */ @@ -144,11 +144,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 500, + orgMaxOrgs: 4000, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 500, + orgStartAmount: 1000, /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, @@ -166,7 +166,7 @@ const Config = { * default value, while organism is delivering. So, if the value is * 1000, then range will be: -500..500 */ - codeVarInitRange: 500, + codeVarInitRange: 10000000, /** * {Number} This value is amount of code lines, which will be run for one * organism without interruption by one VM. Set this value to value bigger diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 0b78742..87563aa 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -34,24 +34,6 @@ const ORG_COLORS = ORG_START_COLOR - ORG_END_COLOR; const UPDATE_COLOR_PERIOD = 50; class Organism extends Observer { - /** - * Returns color by index. Index may be increased without limit - * @param {Number} index Color index. Starts from 0 till MAX_COLORS - * @returns {Number} RGB value - */ - static getColor(index) { - // - // Maximum possible colors for this value is MAX_COLORS - // - const frequency = 0.0005; - - const r = Math.sin(frequency * index ) * 127 + 128; - const g = Math.sin(frequency * index + 2) * 127 + 128; - const b = Math.sin(frequency * index + 4) * 127 + 128; - - return r << 16 | g << 8 | b; - } - /** * Is called before every run. Should return true, if everything * is okay and we don't need to interrupt running. If true, then @@ -230,7 +212,7 @@ class Organism extends Observer { this.vm = new VM(this, this._operatorCls, OConfig.orgOperatorWeights); this._energy = OConfig.orgStartEnergy; this._startEnergy = OConfig.orgStartEnergy; - this._color = Organism.getColor(ORG_END_COLOR); + this._color = Helper.getColor(ORG_END_COLOR); this._mutationProbs = OConfig.orgMutationProbs.slice(); this._mutationPeriod = OConfig.orgRainMutationPeriod; this._mutationPercent = OConfig.orgRainMutationPercent; @@ -253,7 +235,7 @@ class Organism extends Observer { } _updateColor() { - this._color = Organism.getColor(OConfig.orgAlivePeriod === 0 ? ORG_END_COLOR : this._iterations * (ORG_COLORS / OConfig.orgAlivePeriod) + ORG_START_COLOR); + this._color = Helper.getColor(OConfig.orgAlivePeriod === 0 ? ORG_END_COLOR : this._iterations * (ORG_COLORS / OConfig.orgAlivePeriod) + ORG_START_COLOR); } _updateClone() { diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index fd6e86f..722f999 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -64,6 +64,8 @@ class Organisms extends Configurable { this._mutator = new Mutator(manager, this); this._oldOrg = null; this._curOldOrg = null; + this._energy = 0; + this._curEnergy = 0; this._onIterationCb = this._onIteration.bind(this); this._onLoopCb = this._onLoop.bind(this); this._onConfigChange = this._onConfigChange.bind(this); @@ -82,6 +84,10 @@ class Organisms extends Configurable { Helper.unoverride(this.parent, 'onIteration', this._onIterationCb); Helper.unoverride(this.parent, 'onLoop', this._onLoopCb); this.parent.off(EVENTS.CONFIG_CHANGE, this._onConfigChange); + this._energy = 0; + this._curEnergy = 0; + this._curOldOrg = null; + this._oldOrg = null; this._mutator.destroy(); this._mutator = null; this.world = null; @@ -95,16 +101,15 @@ class Organisms extends Configurable { } /** - * Is called at the end of run() method + * Is called at the end of run() method. Found oldest organism and calculates + * energy of all organisms * @param {Organism} org Current organism - * @param {Number} i Current organism index/id */ - onOrganism(org, i) { - if (i === 0) { - this._oldOrg = this._curOldOrg; - this._curOldOrg = org; - } + onOrganism(org) { + if (org.vm === null) {return} + if (this._curOldOrg === null) {this._curOldOrg = org} if (this._curOldOrg.iterations < org.iterations) {this._curOldOrg = org} + this._curEnergy += org.energy; } addOrgHandlers(org) { @@ -117,6 +122,7 @@ class Organisms extends Configurable { reset() { this._orgId = 0; + this.parent.sharedObj.orgEnergy = 0; } move(x1, y1, x2, y2, org) { @@ -173,15 +179,16 @@ class Organisms extends Configurable { for (let i = 0, len = orgs.size; i < len; i++) { if ((org = orgs.get(i)) === null) {continue} org.run(); - this.onOrganism(org, i); + this.onOrganism(org); } + this._onAfterIteration(); this._updateTournament(counter); this._updateRandomOrgs(counter); this._updateCrossover(counter); } - _onLoop() { + _onLoop(counter, stamp, sharedObj) { this._updateCreate(); } @@ -223,7 +230,7 @@ class Organisms extends Configurable { [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(); + let child = this.organisms.added(); if (!child) {return false} this.onClone(org, child); @@ -235,7 +242,7 @@ class Organisms extends Configurable { _crossover(org1, org2) { if (!this._clone(org1, true)) {return false} - let child = this.organisms.last(); + let child = this.organisms.added(); if (child.energy > 0 && org2.energy > 0) { child.changes += (Math.abs(child.vm.crossover(org2.vm)) * Num.MAX_BITS); @@ -250,7 +257,10 @@ class Organisms extends Configurable { this.reset(); for (let i = 0, len = OConfig.orgStartAmount; i < len; i++) { - this.createOrg(...world.getFreePos()); + //this.createOrg(...world.getFreePos()); + const x = Helper.rand(500) + 1920 * 2 - 250; + const y = Helper.rand(500) + 1080 * 2 - 250; + if (world.isFree(x, y)) {this.createOrg(x, y)} } Console.info('Population has created'); } @@ -331,6 +341,14 @@ class Organisms extends Configurable { return true; } + _onAfterIteration() { + this.parent.sharedObj.orgEnergy = this._curEnergy; + this._oldOrg = this._curOldOrg; + this._energy = this._curEnergy; + this._curOldOrg = null; + this._curEnergy = 0; + } + /** * Does tournament between two random organisms and kill looser. In general * this function is a natural selection in our system. diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 818551a..f7834d3 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -240,7 +240,8 @@ class OperatorsDos extends Operators { } if (victim < 0) {return ++line} // World object found. We can't eat objects if (victim === 0) { // Energy found - if ((eat = this._world.grabDot(x, y, eat)) > 0 && org.energy + eat <= OConfig.orgMaxEnergy) { + if ((eat = this._world.grabDot(x, y, eat)) > 0) { + if (org.energy + eat > OConfig.orgMaxEnergy) {eat = OConfig.orgMaxEnergy - org.energy} org.energy += eat; this._obs.fire(EVENTS.EAT_ENERGY, eat); } @@ -291,8 +292,10 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function put(line, num, org) { + return ++line; let put = this.vars[${v0}]; if (put <= 0) {return ++line} + if (put > 0xffffff) {put = 0xffffff} let x = org.dirX; let y = org.dirY; if (!IN_WORLD(x, y)) {return ++line} @@ -359,7 +362,7 @@ class OperatorsDos extends Operators { for (let e = 0; e < 5; e++) { if (energy[e].length === 4) { const xy = energy[e]; - const eat = (2**e) * EConfig.energyAmount; + const eat = (2**e) * Helper.getColor(EConfig.colorIndex); if (org.energy + eat <= OConfig.orgMaxEnergy) { org.energy += eat; @@ -581,7 +584,7 @@ class OperatorsDos extends Operators { let y = org.dirY; if (!IN_WORLD(x, y) || this._world.data[x][y] !== 0 || org.energy <= OConfig.orgPoisonValue) {return ++line} - this._world.setDot(x, y, Organism.getColor(OConfig.orgPoisonColor)); + this._world.setDot(x, y, Helper.getColor(OConfig.orgPoisonColor)); this._positions[x][y] = OBJECT_TYPES.POISON; if ((org.energy -= OConfig.orgPoisonValue) < 0) {org.destroy()} return ++line; diff --git a/client/src/manager/plugins/status/Status.js b/client/src/manager/plugins/status/Status.js index 983ad4d..4c88ad8 100644 --- a/client/src/manager/plugins/status/Status.js +++ b/client/src/manager/plugins/status/Status.js @@ -194,7 +194,7 @@ class Status extends Configurable { status.killin = fix(this._kill[7], 2); status.killclone = fix(this._kill[8], 2); - status.wenergy = fix(this._worldEnergy, 5); + status.wenergy = fix(this._worldEnergy, 7); !this._firstCall && this.onStatus(status, orgs.length); this._onAfterLoop(stamp); diff --git a/client/src/manager/plugins/stones/Config.js b/client/src/manager/plugins/stones/Config.js index 55f0ef6..b9cdda7 100644 --- a/client/src/manager/plugins/stones/Config.js +++ b/client/src/manager/plugins/stones/Config.js @@ -3,7 +3,10 @@ * * @author flatline */ -const Config = { +const Helper = require('./../../../../../common/src/Helper'); + +const STONES_COLOR = 1800; +const Config = { /** * {Number} size of one stone block in dots */ @@ -11,11 +14,11 @@ const Config = { /** * {Number} Index of stone color. Starts from 0. Ends with Organism.MAX_COLORS */ - colorIndex: 1800, + colorIndex: STONES_COLOR, /** - * {Number} Percent from all dots in a world until stones will be added. + * {Number} Maximum amount of stone dots */ - maxPercent: .03, + maxValue: 500000 * Helper.getColor(STONES_COLOR), /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high stones concentration. @@ -23,7 +26,7 @@ const Config = { * example all the screen will be filled by stones. As many values by four, you set as * many places with stones will be created. In case of null, grouping will be disabled. */ - groups: [1920 * 3, 1080 * 2, 1920 * 2, 1080 * 4] + groups: [1920 * 2, 1080 * 2, 1920 * 2, 1080 * 4] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/share/Dots.js b/client/src/share/Dots.js index 24c0d32..af1583c 100644 --- a/client/src/share/Dots.js +++ b/client/src/share/Dots.js @@ -8,9 +8,17 @@ const Helper = require('../../../common/src/Helper'); const Configurable = require('../../../common/src/Configurable'); const Config = require('./Config').Config; -const Organism = require('../manager/plugins/organisms/Organism').Organism; class Dots extends Configurable { + /** + * Override of Manager.onLoop() method + * @param {Number} counter Global time analog + * @param {Number} timer UNIX time stamp + * @param {Object} sharedObj Shared object of the manager + * @abstract + */ + onLoop(counter, timer, sharedObj) {} + /** * Creates dots object. You have to inherit your class from this one * to have specified type of object. For example: stone or energy. @@ -24,37 +32,44 @@ class Dots extends Configurable { this.manager = manager; this._cfg = cfg; - this._config = config; + this.config = config; this._onIterationCb = this.onIteration.bind(this); + this._onLoopCb = this.onLoop.bind(this); Helper.override(manager, 'onIteration', this._onIterationCb); + Helper.override(manager, 'onLoop', this._onLoopCb); } destroy() { + Helper.unoverride(this.manager, 'onLoop', this._onLoopCb); Helper.unoverride(this.manager, 'onIteration', this._onIterationCb); + this._onLoopCb = null; this._onIterationCb = null; this._cfg = null; - this._config = null; + this.config = null; this.manager = null; } onIteration(counter) { const cfg = this._cfg; - const config = this._config; + const config = this.config; // // We have to add dots only once // - if (cfg.addOnce && counter < 1 && config.maxPercent !== .0) {this._addDots(); return false} + if (cfg.addOnce && counter < 1 && config.maxValue !== 0) {this._addDots(); return false} // // We have to add dots every time, when minimum percent of dots is reached // if (config.checkPeriod === 0 || counter % config.checkPeriod !== 0) {return false} - const dotsPercent = this._getDotsPercent(cfg.compareCb); - if (dotsPercent > config.minPercent) {return dotsPercent} + const dotsValue = this._getDotsValue(cfg.compareCb); + if (cfg.checkMin) { + const percent = cfg.checkMin.call(this, dotsValue); + if (!percent) {return dotsValue} + } else if (dotsValue > config.minValue) {return dotsValue} this._addDots(); - return dotsPercent; + return this._getDotsValue(cfg.compareCb); } /** @@ -63,22 +78,23 @@ class Dots extends Configurable { * @param {Function} compareCb Compare function. Returns true/false * @return {Number} Percent */ - _getDotsPercent(compareCb) { + _getDotsValue(compareCb) { let dots = 0; const width = Config.worldWidth; const height = Config.worldHeight; + const world = this.manager.world; for (let x = 0; x < width; x++) { for (let y = 0; y < height; y++) { - if (compareCb(x, y)) {++dots} + if (compareCb(x, y)) {dots += world.getDot(x, y)} } } - return dots / (width * height); + return dots; } _addDots() { - const dots = this._config.maxPercent * Config.worldWidth * Config.worldHeight; + const dots = this.config.maxValue; let amount = 0; let attempts = 0; while (amount < dots && attempts < 100) { @@ -95,13 +111,13 @@ class Dots extends Configurable { _addDotsBlock(amount, dots) { const width = Config.worldWidth; const height = Config.worldHeight; - const color = Organism.getColor(this._config.colorIndex); + const color = Helper.getColor(this.config.colorIndex); const man = this.manager; const world = man.world; - const blockSize = this._config.blockSize; + const blockSize = this.config.blockSize; const setCb = this._cfg.setCb; const colorCb = this._cfg.colorCb; - const groups = this._config.groups; + const groups = this.config.groups; const rand = Helper.rand; const groupAmount = groups ? groups.length : 0; const xCoord = rand(groupAmount / 4) * 4; @@ -114,9 +130,10 @@ class Dots extends Configurable { y = y + Helper.rand(3) - 1; if (x < 0 || x >= width || y < 0 || y >= height) {return amount} if (world.isFree(x, y)) { - if (world.setDot(x, y, colorCb ? colorCb(x, y) : color)) { + const c = colorCb ? colorCb(x, y) : color; + if (world.setDot(x, y, c)) { setCb && setCb(x,y); - if (++amount >= dots) {return amount} + if ((amount += c) >= dots) {return amount} } } } diff --git a/common/src/FastArray.js b/common/src/FastArray.js index d8445f0..4628136 100644 --- a/common/src/FastArray.js +++ b/common/src/FastArray.js @@ -1,12 +1,18 @@ /** - * Implementation of fast array. This class uses fixed array size. Second that - * get() method will be called must of the time, then set() or del() or resize(). - * Resize is possible, but should be rare to keep it fast. Is used for storing - * organisms population. Removing element means setting null to specified index. + * Implementation of fast array. Meaning of this class is in fast access to custom + * element of array, ability to add/remove elements. First, this class uses fixed + * array size. Second, get() method will be called must of the time, then set() or + * del() or resize(). Resize is possible, but should be rare to keep it fast. Is + * used for storing organisms population. Removing element means setting null to + * specified index. * * @author flatline */ class FastArray { + /** + * Creates fast array instance. Size is maximum amount of elements you may access to + * @param {Number} size Max elements in a array + */ constructor(size) { /** * {Array} Source container for custom objects @@ -38,12 +44,14 @@ class FastArray { this._arr = null; this._freeIndexes = null; this._size = null; + this._index = -1; } /** * Analog of Array.length - * @returns {Number} Amount of not empty elements in FastArray. - * Not all cells in an array may be filled by values. + * @returns {Number} Amount of not empty elements in FastArray. + * Not all cells in an array may be filled by values. 0 or less + * then zero means no items in an array. */ get length() {return this._size - this._index - 1} @@ -54,8 +62,8 @@ class FastArray { get size() {return this._size} /** - * Returns next free index in FastArray - * @returns {Number} + * Returns next free index in FastArray or undefined if there is no free index + * @returns {Number|undefined} */ get freeIndex() { return this._freeIndexes[this._index]; @@ -64,7 +72,7 @@ class FastArray { /** * Sets value to FastArray. You can't set value index due to * optimization reason. Only a value - * @param {*} v Any value except number + * @param {*|false} v Any value or false if value hasn't added */ add(v) {this._index > -1 && (this._arr[this._freeIndexes[this._index--]] = v)} @@ -76,7 +84,7 @@ class FastArray { get(i) {return this._arr[i]} /** - * Removes a value by index + * Removes(sets it to null) a value by index. * @param {Number} i Value index */ del(i) { @@ -88,25 +96,25 @@ class FastArray { /** * Returns last added value by set() method - * @returns {*} Value + * @returns {*|undefined} Value or undefined if there is no value */ - last() { + added() { return this._arr[this._freeIndexes[this._index + 1]]; } /** - * Resizes an array. Values will not be removed during resize. + * Resize 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++) { - typeof arr[i] === 'undefined' && (arr[i] = null); - arr[i] === null && (indexes[++this._index] = i); + if (size <= 0) {return} + const oldArr = this._arr.slice(); + const oldSize = Math.min(this._size, size); + + this.constructor(size); + for (let i = 0; i < oldSize; i++) { + oldArr[i] !== null && this.add(oldArr[i]); } } } diff --git a/common/src/FastArraySpec.js b/common/src/FastArraySpec.js index 678856e..f4e9f9b 100644 --- a/common/src/FastArraySpec.js +++ b/common/src/FastArraySpec.js @@ -10,6 +10,7 @@ describe('common/src/FastArray', () => { expect(fa.size).toEqual(size); expect(fa.length).toEqual(0); expect(fa.freeIndex).toEqual(size - 1); + expect(fa.added()).toEqual(undefined); }); it('Checking destroy', () => { @@ -17,10 +18,13 @@ describe('common/src/FastArray', () => { const fa1 = new FastArray(fSize); expect(fa1.size).toEqual(fSize); fa1.destroy(); + expect(fa1.length <= 0).toBe(true); expect(fa1.size).toEqual(null); + fa1.add({}); + expect(fa1.length <= 0).toBe(true); }); - it('Checking length property', () => { + it('Checking length getter', () => { fa.add({}); expect(fa.length).toEqual(1); fa.get(size - 1); @@ -38,11 +42,91 @@ describe('common/src/FastArray', () => { expect(fa.length).toEqual(2); }); - it('Checking size property', () => { + it('Checking size getter', () => { expect(fa.size).toEqual(size); fa.add({}); expect(fa.size).toEqual(size); fa.del(size - 1); expect(fa.size).toEqual(size); + + for (let i = 0; i < size; i++) {fa.add({})} + expect(fa.size).toEqual(size); + fa.add([]); + expect(fa.size).toEqual(size); + + fa.resize(size - 1); + expect(fa.size).toEqual(size - 1); + }); + + it('Checking freeIndex getter', () => { + fa.add({}); + expect(fa.freeIndex).toEqual(size - 2); + fa.del(size - 1); + expect(fa.freeIndex).toEqual(size - 1); + for (let i = 0; i < size; i++) {fa.add({})} + expect(fa.freeIndex).toEqual(undefined); + fa.del(size - 1); + expect(fa.freeIndex).toEqual(size - 1); + }); + + it('Checking add() method', () => { + const obj = {}; + fa.add(obj); + expect(fa.length).toEqual(1); + expect(fa.added()).toEqual(obj); + fa.del(size - 1); + expect(fa.get(size - 1)).toEqual(null); + + for (let i = 0; i < size; i++) {fa.add({})} + expect(fa.length).toEqual(size); + }); + + it('Checking get() method', () => { + const obj = {}; + expect(fa.get(size - 1)).toEqual(null); + expect(fa.get(size - 1)).toEqual(null); + fa.add(obj); + expect(fa.get(size - 1)).toEqual(obj); + expect(fa.get(size - 1)).toEqual(obj); + fa.del(size - 1); + expect(fa.get(size - 1)).toEqual(null); + fa.add(obj); + expect(fa.get(size - 1)).toEqual(obj); + fa.resize(size - 1); + expect(fa.get(size - 1)).toEqual(undefined); + }); + + it('Checking del() method', () => { + const obj = {}; + fa.add(obj); + expect(fa.added()).toEqual(obj); + fa.del(size - 1); + expect(fa.added()).toEqual(undefined); + fa.del(size - 1); + expect(fa.added()).toEqual(undefined); + fa.del(size); + expect(fa.added()).toEqual(undefined); + }); + + it('Checking added() method', () => { + const obj = {}; + expect(fa.added()).toEqual(undefined); + fa.add(obj); + expect(fa.added()).toEqual(obj); + expect(fa.added()).toEqual(obj); + fa.del(size - 1); + expect(fa.added()).toEqual(undefined); + fa.add(obj); + expect(fa.added()).toEqual(obj); + fa.resize(size + 1); + expect(fa.added()).toEqual(obj); + }); + + it('Checking resize() method', () => { + const obj = {}; + fa.add(obj); + expect(fa.added()).toEqual(obj); + fa.resize(size + 1); + expect(fa.added()).toEqual(obj); }); }); \ No newline at end of file diff --git a/common/src/Helper.js b/common/src/Helper.js index 299d4d8..990c376 100644 --- a/common/src/Helper.js +++ b/common/src/Helper.js @@ -8,6 +8,23 @@ const Config = require('./../../client/src/share/Config').Config; const DIR = require('./Directions').DIR; class Helper { + /** + * Returns color by index. Index may be increased without limit + * @param {Number} index Color index. Starts from 0 till 10000 + * @returns {Number} RGB value + */ + static getColor(index) { + // + // Maximum possible colors for this value is MAX_COLORS + // + const frequency = 0.0005; + + const r = Math.sin(frequency * index ) * 127 + 128; + const g = Math.sin(frequency * index + 2) * 127 + 128; + const b = Math.sin(frequency * index + 4) * 127 + 128; + + return r << 16 | g << 8 | b; + } /** * Makes synchronous delay * @param {Number} ms Amount of milliseconds to delay diff --git a/tests/jasmine.json b/tests/jasmine.json index dead352..479a220 100644 --- a/tests/jasmine.json +++ b/tests/jasmine.json @@ -1,9 +1,10 @@ { "spec_dir": "./", "spec_files": [ - "client/src/**/*[sS]pec.js", - "common/src/**/*[sS]pec.js", - "server/src/**/*[sS]pec.js" + "1client/src/**/*[sS]pec.js", + "1common/src/**/*[sS]pec.js", + "1server/src/**/*[sS]pec.js", + "common/src/FastArraySpec.js" ], "stopSpecOnExpectationFailure": false, "random": false From 39d73d585f8a922ee425cec9e1673d219a4ea539 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 2 May 2018 23:28:40 +0300 Subject: [PATCH 18/88] added tests for vars, consts --- client/src/vm/Operators.js | 61 ++++------ client/src/vm/OperatorsSpec.js | 204 +++++++++++++++++++++++++++++++++ common/src/Helper.js | 21 ++++ 3 files changed, 246 insertions(+), 40 deletions(-) create mode 100644 client/src/vm/OperatorsSpec.js diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 93d20cb..cf134a5 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -6,6 +6,7 @@ */ const OConfig = require('./../manager/plugins/organisms/Config'); const Num = require('./Num'); +const Helper = require('./../../../common/src/Helper'); const OPERATOR_AMOUNT = 11; const MAX_STACK_SIZE = 10000; @@ -95,26 +96,6 @@ class Operators { this._compileFromMem(); // 10 } - /** - * Converts string BIN number representation into number. Removes spaces. - * @param {String} s BIN string. e.g.: 'aa bb cc' -> 0xaabbcc - * @param {Number} width Amount of digits in binary number - * @returns {Number} - */ - static _toHexNum(s, width = 0) { - return parseInt(s.split(' ').join('').padStart(width, '0'), 2) - } - - /** - * Converts number to binary string - * @param {Number} n Number to convert - * @param {Number} width Amount of digits in binary number - * @return {String} Binary string - */ - static _toBinStr(n, width = 0) { - return n.toString(2).padStart(width, '0'); - } - /** * Compiles all variants of var operator and stores they in * this._compiledOperators map. 'xx' means, that amount of bits @@ -128,8 +109,8 @@ class Operators { static _compileVar() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -156,10 +137,10 @@ class Operators { static _compileConst() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const bits = Num.MAX_BITS - OConfig.codeConstBits; - const bits1var = Num.BITS_OF_VAR0; + const bits1var = Num.BITS_OF_VAR1; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -184,8 +165,8 @@ class Operators { static _compileIf() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let c = 0; c < Math.pow(2, this.CONDITION_BITS); c++) { @@ -214,8 +195,8 @@ class Operators { static _compileLoop() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let c = 0; c < Math.pow(2, this.CONDITION_BITS); c++) { @@ -244,8 +225,8 @@ class Operators { static _compileOperator() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); const opsLen = Math.pow(2, this.FOUR_BITS); @@ -276,7 +257,7 @@ class Operators { */ static _compileFunc() { const ops = this._compiledOperators; - const h = this._toHexNum; + const h = Helper.toHexNum; eval(`Operators.global.fn = function func(line) {return this.offs[line] === line ? ++line : this.offs[line]}`); ops[h(`${'100101'}`)] = this.global.fn; @@ -296,7 +277,7 @@ class Operators { */ static _compileFuncCall() { const ops = this._compiledOperators; - const h = this._toHexNum; + const h = Helper.toHexNum; const ifBit = Num.MAX_BITS - 1; const fnBits = Num.MAX_BITS - this.FUNC_NAME_BITS; const funcs = Math.pow(2, this.FUNC_NAME_BITS); @@ -307,7 +288,7 @@ class Operators { const data = num << ${opBits}; const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data >>> ${fnBits}]; if (typeof offs !== 'undefined') { - if (this.stack.length > MAX_STACK_SIZE * 3) { + if (this.stack.length > ${MAX_STACK_SIZE} * 3) { org.energy -= org.vm.size; return ++line; } @@ -331,7 +312,7 @@ class Operators { */ static _compileReturn() { const ops = this._compiledOperators; - const h = this._toHexNum; + const h = Helper.toHexNum; const vars = Math.pow(2, OConfig.codeBitsPerVar); eval(`Operators.global.fn = function ret(line) { @@ -359,7 +340,7 @@ class Operators { */ static _compileBracket() { const ops = this._compiledOperators; - const h = this._toHexNum; + const h = Helper.toHexNum; const vars = Math.pow(2, OConfig.codeBitsPerVar); const opMask = Num.OPERATOR_MASK_OFF; @@ -395,8 +376,8 @@ class Operators { static _compileToMem() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); const memLen = Math.pow(2, OConfig.orgMemBits) - 1; @@ -425,8 +406,8 @@ class Operators { static _compileFromMem() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); const memLen = Math.pow(2, OConfig.orgMemBits) - 1; diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js new file mode 100644 index 0000000..1595b55 --- /dev/null +++ b/client/src/vm/OperatorsSpec.js @@ -0,0 +1,204 @@ +const Operators = require('./Operators'); +const OConfig = require('./../manager/plugins/organisms/Config'); +const Helper = require('./../../../common/src/Helper'); + +describe("client/src/vm/Operators", () => { + const h = Helper.toHexNum; + let cbpv; + let ccb; + let ops; + let offs; + let vars; + + beforeAll (() => { + cbpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 2; + ccb = OConfig.codeConstBits; + OConfig.codeConstBits = 3; + Operators.compile(); + }); + afterAll(() => { + OConfig.codeBitsPerVar = cbpv; + OConfig.codeConstBits = ccb; + }); + beforeEach(() => { + vars = [0,1,2,3]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + }); + + describe('Creation and destroy', () => { + it('Checks creation', () => { + expect(ops.offs).toEqual(offs); + expect(ops.vars).toEqual(vars); + expect(Array.isArray(ops.stack)).toEqual(true); + expect(Array.isArray(ops.funcs)).toEqual(true); + expect(Object.keys(ops.operators).length > 0).toEqual(true); + }); + + it('Checks simple destroy', () => { + const ops2 = new Operators(offs, vars); + const offs2 = offs; + const vars2 = vars; + expect(ops2.offs).toEqual(offs); + expect(ops2.vars).toEqual(vars); + expect(Array.isArray(ops2.stack)).toEqual(true); + expect(Array.isArray(ops2.funcs)).toEqual(true); + expect(Object.keys(ops.operators).length > 0).toEqual(true); + ops2.destroy(); + expect(ops2.offs).toEqual(null); + expect(ops2.vars).toEqual(null); + expect(ops2.stack).toEqual(null); + expect(ops2.funcs).toEqual(null); + expect(ops2.operators).toEqual(null); + expect(offs2).toEqual(offs); + expect(vars2).toEqual(vars); + }); + }); + + describe('var', () => { + it('Checks v0=v1', () => { + expect(ops.operators[h('100000 00 01')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3]); + }); + it('Checks v0=v0', () => { + expect(ops.operators[h('100000 00 00')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3]); + }); + it('Checks v0=v3', () => { + expect(ops.operators[h('100000 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([3,1,2,3]); + }); + it('Checks v3=v3', () => { + expect(ops.operators[h('100000 11 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3]); + }); + it('Checks correct line return', () => { + expect(ops.operators[h('100000 11 11')].call(ops, 0)).toEqual(1); + expect(ops.operators[h('100000 11 01')].call(ops, 1)).toEqual(2); + expect(ops.operators[h('100000 01 11')].call(ops, 100)).toEqual(101); + }); + describe('var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Checks v0=v1', () => { + expect(ops.operators[h('100000 000 001')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + }); + it('Checks v0=v0', () => { + expect(ops.operators[h('100000 000 000')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + }); + it('Checks v0=v3', () => { + expect(ops.operators[h('100000 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([3,1,2,3,4,5,6,7]); + }); + it('Checks v7=v7', () => { + expect(ops.operators[h('100000 111 111')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + }); + it('Checks correct line return', () => { + expect(ops.operators[h('100000 011 011')].call(ops, 0)).toEqual(1); + expect(ops.operators[h('100000 011 001')].call(ops, 1)).toEqual(2); + expect(ops.operators[h('100000 001 011')].call(ops, 100)).toEqual(101); + }); + }); + }); + + describe('const', () => { + it('Checks v0=1', () => { + expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 000000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3]); + }); + it('Checks v0=0', () => { + expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 000 000000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3]); + }); + it('Checks v0=3', () => { + expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 011 000000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([3,1,2,3]); + }); + it('Checks v3=3', () => { + expect(ops.operators[h('100001 11')].call(ops, 0, h('100001 11 011 000000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3]); + }); + it('Checks correct line return', () => { + expect(ops.operators[h('100001 11')].call(ops, 0, h('100001 11 011 000000000000000000000'))).toEqual(1); + expect(ops.operators[h('100001 11')].call(ops, 1, h('100001 11 001 000000000000000000000'))).toEqual(2); + expect(ops.operators[h('100001 01')].call(ops, 100, h('100001 01 011 000000000000000000000'))).toEqual(101); + }); + describe('var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Checks v0=1', () => { + expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 001 00000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + }); + it('Checks v0=0', () => { + expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 000 00000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + }); + it('Checks v0=3', () => { + expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 011 00000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([3,1,2,3,4,5,6,7]); + }); + it('Checks v7=7', () => { + expect(ops.operators[h('100001 111')].call(ops, 0, h('100001 000 111 00000000000000000000'))).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + }); + it('Checks correct line return', () => { + expect(ops.operators[h('100001 011')].call(ops, 0, h('100001 011 011 00000000000000000000'))).toEqual(1); + expect(ops.operators[h('100001 011')].call(ops, 1, h('100001 011 001 00000000000000000000'))).toEqual(2); + expect(ops.operators[h('100001 001')].call(ops, 100, h('100001 001 011 00000000000000000000'))).toEqual(101); + }); + }); + }); +}); \ No newline at end of file diff --git a/common/src/Helper.js b/common/src/Helper.js index 990c376..077a9de 100644 --- a/common/src/Helper.js +++ b/common/src/Helper.js @@ -267,6 +267,27 @@ class Helper { return typeof v === 'function'; } + + /** + * Converts string BIN number representation into number. Removes spaces. + * @param {String} s BIN string. e.g.: 'aa bb cc' -> 0xaabbcc + * @param {Number} width Amount of digits in binary number + * @returns {Number} + */ + static toHexNum(s, width = 0) { + return parseInt(s.split(' ').join('').padStart(width, '0'), 2) + } + + /** + * Converts number to binary string + * @param {Number} n Number to convert + * @param {Number} width Amount of digits in binary number + * @return {String} Binary string + */ + static toBinStr(n, width = 0) { + return n.toString(2).padStart(width, '0'); + } + /** * Generates unique numeric ids * @returns {Number} From 1700a354dfd630a3bf3a81eb1abe57561f092eba Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 4 May 2018 11:09:04 +0300 Subject: [PATCH 19/88] added new tests #145 --- client/src/vm/OperatorsSpec.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 1595b55..0f0d03d 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -62,7 +62,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('var', () => { + describe('vars 2bits per var', () => { it('Checks v0=v1', () => { expect(ops.operators[h('100000 00 01')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -84,7 +84,14 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100000 11 01')].call(ops, 1)).toEqual(2); expect(ops.operators[h('100000 01 11')].call(ops, 100)).toEqual(101); }); - describe('var', () => { + it('Garbage in a tail should not affect vars', () => { + expect(ops.operators[h('100000 00 01')].call(ops, 0, h('100000 00 01 111111111111111111111'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3]); + expect(ops.operators[h('100000 00 00')].call(ops, 0, h('100000 00 00 111111111111111111111'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3]); + }); + + describe('vars 3bits per var', () => { let bpv; let ops; let vars; @@ -129,10 +136,16 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100000 011 001')].call(ops, 1)).toEqual(2); expect(ops.operators[h('100000 001 011')].call(ops, 100)).toEqual(101); }); + it('Garbage in a tail should not affect vars', () => { + expect(ops.operators[h('100000 000 001')].call(ops, 0, h('100000 000 001 11111111111111111111'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + expect(ops.operators[h('100000 000 000')].call(ops, 0, h('100000 000 000 11111111111111111111'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + }); }); }); - describe('const', () => { + describe('consts 2bits per var', () => { it('Checks v0=1', () => { expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 000000000000000000000'))).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -154,7 +167,14 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100001 11')].call(ops, 1, h('100001 11 001 000000000000000000000'))).toEqual(2); expect(ops.operators[h('100001 01')].call(ops, 100, h('100001 01 011 000000000000000000000'))).toEqual(101); }); - describe('var', () => { + it('Garbage in a tail should not affect vars', () => { + expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 111111111111111111111'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3]); + expect(ops.operators[h('100001 00')].call(ops, 1, h('100001 00 000 111111111111111111111'))).toEqual(2); + expect(ops.vars).toEqual([0,1,2,3]); + }); + + describe('consts 3bits per var', () => { let bpv; let ops; let vars; From e5e86f6180df7e72fe64245a2bf635b552f27409 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 4 May 2018 22:40:04 +0300 Subject: [PATCH 20/88] added tests for vars, consts #145 --- client/src/vm/OperatorsSpec.js | 36 ++++++++++++++++++++++++++++++++++ tests/jasmine.json | 3 ++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 0f0d03d..abe651a 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -219,6 +219,42 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100001 011')].call(ops, 1, h('100001 011 001 00000000000000000000'))).toEqual(2); expect(ops.operators[h('100001 001')].call(ops, 100, h('100001 001 011 00000000000000000000'))).toEqual(101); }); + it('Garbage in a tail should not affect vars', () => { + expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 001 11111111111111111111'))).toEqual(1); + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + expect(ops.operators[h('100001 000')].call(ops, 1, h('100001 000 000 11111111111111111111'))).toEqual(2); + expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + }); + }); + }); + + describe('conditions 2bits per var', () => { + it('if(v3!==v3) should be false', () => { + const code = [ + h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1110')].call(ops, 0)).toEqual(3); + }); + it('if(v0+v1) should be true', () => { + const code = [ + h('100010 00 01 0000 000000000000000000'), // if (v0+v1) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 0000')].call(ops, 0)).toEqual(1); + }); + it('if(v3===v3) should be false', () => { + const code = [ + h('100010 11 11 1101 000000000000000000'), // if (v3===v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1101')].call(ops, 0)).toEqual(1); }); }); }); \ No newline at end of file diff --git a/tests/jasmine.json b/tests/jasmine.json index 479a220..0b4a9cd 100644 --- a/tests/jasmine.json +++ b/tests/jasmine.json @@ -4,7 +4,8 @@ "1client/src/**/*[sS]pec.js", "1common/src/**/*[sS]pec.js", "1server/src/**/*[sS]pec.js", - "common/src/FastArraySpec.js" + "common/src/FastArraySpec.js", + "client/src/vm/OperatorsSpec.js" ], "stopSpecOnExpectationFailure": false, "random": false From 6624153a0605c53bb8cd0e176b031347dded27a0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 5 May 2018 11:16:11 +0300 Subject: [PATCH 21/88] added tests for ifs #145 --- client/src/vm/OperatorsSpec.js | 59 ++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index abe651a..f75d030 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -247,14 +247,67 @@ describe("client/src/vm/Operators", () => { ops.updateIndexes(code); expect(ops.operators[h('100010 11 11 0000')].call(ops, 0)).toEqual(1); }); - it('if(v3===v3) should be false', () => { + it('if(v0<=v0) should be false', () => { const code = [ - h('100010 11 11 1101 000000000000000000'), // if (v3===v3) { + h('100010 00 00 1111 000000000000000000'), // if (v0<=v0) { h('100000 00 01 1111111111111111111111'), // v0 = v1 h('101000 00000000000000000000000000') // } ]; ops.updateIndexes(code); - expect(ops.operators[h('100010 11 11 1101')].call(ops, 0)).toEqual(1); + expect(ops.operators[h('100010 00 00 1111')].call(ops, 0)).toEqual(1); }); + + // describe('ifs 3bits per var', () => { + // let bpv; + // let ops; + // let vars; + // let offs; + // beforeAll (() => { + // bpv = OConfig.codeBitsPerVar; + // OConfig.codeBitsPerVar = 3; + // Operators.compile(); + // }); + // afterAll (() => Operators.compile()); + // beforeEach(() => { + // vars = [0,1,2,3,4,5,6,7]; + // offs = new Array(10); + // ops = new Operators(offs, vars); + // }); + // afterEach (() => { + // ops.destroy(); + // ops = null; + // offs = null; + // vars = null; + // OConfig.codeBitsPerVar = bpv; + // }); + // + // it('Checks v0=1', () => { + // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 001 00000000000000000000'))).toEqual(1); + // expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + // }); + // it('Checks v0=0', () => { + // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 000 00000000000000000000'))).toEqual(1); + // expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + // }); + // it('Checks v0=3', () => { + // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 011 00000000000000000000'))).toEqual(1); + // expect(ops.vars).toEqual([3,1,2,3,4,5,6,7]); + // }); + // it('Checks v7=7', () => { + // expect(ops.operators[h('100001 111')].call(ops, 0, h('100001 000 111 00000000000000000000'))).toEqual(1); + // expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + // }); + // it('Checks correct line return', () => { + // expect(ops.operators[h('100001 011')].call(ops, 0, h('100001 011 011 00000000000000000000'))).toEqual(1); + // expect(ops.operators[h('100001 011')].call(ops, 1, h('100001 011 001 00000000000000000000'))).toEqual(2); + // expect(ops.operators[h('100001 001')].call(ops, 100, h('100001 001 011 00000000000000000000'))).toEqual(101); + // }); + // it('Garbage in a tail should not affect vars', () => { + // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 001 11111111111111111111'))).toEqual(1); + // expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + // expect(ops.operators[h('100001 000')].call(ops, 1, h('100001 000 000 11111111111111111111'))).toEqual(2); + // expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + // }); + // }); }); }); \ No newline at end of file From 27b3ca9e2d453d5804921c294f1383bb58334d25 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 6 May 2018 13:55:22 +0300 Subject: [PATCH 22/88] added tests for loops #145 --- client/src/vm/Operators.js | 4 +- client/src/vm/OperatorsSpec.js | 236 +++++++++++++++++++++++++-------- 2 files changed, 182 insertions(+), 58 deletions(-) diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index cf134a5..13baa1e 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -188,7 +188,7 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 6 xx xx 2 + * bits : 6 xx xx 4 * number: 100011 00 01 00... * string: while (v0 < v1) { */ @@ -346,7 +346,7 @@ class Operators { eval(`Operators.global.fn = function bracket(line, num, org, lines) { const startLine = this.offs[line]; - const operator = (lines[startLine] & ${opMask}) >>> Num.VAR_BITS_OFFS; + const operator = typeof startLine === 'undefined' ? -1 : (lines[startLine] & ${opMask}) >>> Num.VAR_BITS_OFFS; if (operator === 0x3) {return this.offs[line]} // loop if (operator === 0x5) { // func const stack = this.stack; diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index f75d030..24c79d5 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -33,7 +33,7 @@ describe("client/src/vm/Operators", () => { vars = null; }); - describe('Creation and destroy', () => { + xdescribe('Creation and destroy', () => { it('Checks creation', () => { expect(ops.offs).toEqual(offs); expect(ops.vars).toEqual(vars); @@ -62,7 +62,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('vars 2bits per var', () => { + xdescribe('vars 2bits per var', () => { it('Checks v0=v1', () => { expect(ops.operators[h('100000 00 01')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -145,7 +145,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('consts 2bits per var', () => { + xdescribe('consts 2bits per var', () => { it('Checks v0=1', () => { expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 000000000000000000000'))).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -228,7 +228,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('conditions 2bits per var', () => { + xdescribe('ifs 2bits per var', () => { it('if(v3!==v3) should be false', () => { const code = [ h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { @@ -256,58 +256,182 @@ describe("client/src/vm/Operators", () => { ops.updateIndexes(code); expect(ops.operators[h('100010 00 00 1111')].call(ops, 0)).toEqual(1); }); + it('Garbage in a tail should not affect if', () => { + const code = [ + h('100010 00 01 0000 111111111111111111'), // if (v0+v1) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 11111111111111111111111111') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 0000')].call(ops, 0)).toEqual(1); + }); + it('Test of one if and two closed brackets', () => { + const code = [ + h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1110')].call(ops, 0)).toEqual(3); + }); + it('Test of one if and two closed brackets 2', () => { + const code = [ + h('101000 00000000000000000000000000'), // } + h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1110')].call(ops, 1)).toEqual(4); + }); + it('if(false) without closed bracket should go to the next line', () => { + const code = [ + h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { + h('100000 00 01 1111111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1110')].call(ops, 0)).toEqual(1); + }); + it('if(true) without closed bracket should go to the next line', () => { + const code = [ + h('100010 11 11 1101 000000000000000000'), // if (v3===v3) { + h('100000 00 01 1111111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1101')].call(ops, 0)).toEqual(1); + }); + + describe('ifs 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); - // describe('ifs 3bits per var', () => { - // let bpv; - // let ops; - // let vars; - // let offs; - // beforeAll (() => { - // bpv = OConfig.codeBitsPerVar; - // OConfig.codeBitsPerVar = 3; - // Operators.compile(); - // }); - // afterAll (() => Operators.compile()); - // beforeEach(() => { - // vars = [0,1,2,3,4,5,6,7]; - // offs = new Array(10); - // ops = new Operators(offs, vars); - // }); - // afterEach (() => { - // ops.destroy(); - // ops = null; - // offs = null; - // vars = null; - // OConfig.codeBitsPerVar = bpv; - // }); - // - // it('Checks v0=1', () => { - // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 001 00000000000000000000'))).toEqual(1); - // expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); - // }); - // it('Checks v0=0', () => { - // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 000 00000000000000000000'))).toEqual(1); - // expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); - // }); - // it('Checks v0=3', () => { - // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 011 00000000000000000000'))).toEqual(1); - // expect(ops.vars).toEqual([3,1,2,3,4,5,6,7]); - // }); - // it('Checks v7=7', () => { - // expect(ops.operators[h('100001 111')].call(ops, 0, h('100001 000 111 00000000000000000000'))).toEqual(1); - // expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); - // }); - // it('Checks correct line return', () => { - // expect(ops.operators[h('100001 011')].call(ops, 0, h('100001 011 011 00000000000000000000'))).toEqual(1); - // expect(ops.operators[h('100001 011')].call(ops, 1, h('100001 011 001 00000000000000000000'))).toEqual(2); - // expect(ops.operators[h('100001 001')].call(ops, 100, h('100001 001 011 00000000000000000000'))).toEqual(101); - // }); - // it('Garbage in a tail should not affect vars', () => { - // expect(ops.operators[h('100001 000')].call(ops, 0, h('100001 000 001 11111111111111111111'))).toEqual(1); - // expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); - // expect(ops.operators[h('100001 000')].call(ops, 1, h('100001 000 000 11111111111111111111'))).toEqual(2); - // expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); - // }); - // }); + it('if(v3!==v3) should be false', () => { + const code = [ + h('100010 011 011 1110 0000000000000000'), // if (v3!==v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 011 011 1110')].call(ops, 0)).toEqual(3); + }); + it('if(v0+v1) should be true', () => { + const code = [ + h('100010 000 001 0000 0000000000000000'), // if (v0+v1) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 011 011 0000')].call(ops, 0)).toEqual(1); + }); + it('if(v0<=v0) should be false', () => { + const code = [ + h('100010 000 000 1111 0000000000000000'), // if (v0<=v0) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 000 000 1111')].call(ops, 0)).toEqual(1); + }); + it('Garbage in a tail should not affect if', () => { + const code = [ + h('100010 000 001 0000 1111111111111111'), // if (v0+v1) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 11111111111111111111111111') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 011 011 0000')].call(ops, 0)).toEqual(1); + }); + it('Test of one if and two closed brackets', () => { + const code = [ + h('100010 011 011 1110 0000000000000000'), // if (v3!==v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 011 011 1110')].call(ops, 0)).toEqual(3); + }); + it('Test of one if and two closed brackets 2', () => { + const code = [ + h('101000 00000000000000000000000000'), // } + h('100010 011 011 1110 0000000000000000'), // if (v3!==v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('101000')].call(ops, 0, code[0])).toEqual(1); + expect(ops.operators[h('100010 011 011 1110')].call(ops, 1)).toEqual(4); + }); + it('if(false) without closed bracket should go to the next line', () => { + const code = [ + h('100010 011 011 1110 0000000000000000'), // if (v3!==v3) { + h('100000 000 001 11111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 011 011 1110')].call(ops, 0)).toEqual(1); + }); + it('if(true) without closed bracket should go to the next line', () => { + const code = [ + h('100010 011 011 1101 0000000000000000'), // if (v3===v3) { + h('100000 000 001 11111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 011 011 1101')].call(ops, 0)).toEqual(1); + }); + }); + }); + + describe('loops 2bits per var', () => { + it('while() with false condition should go outside the closed bracket', () => { + const code = [ + h('100011 11 11 1110 000000000000000000'), // while (v3!==v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 11 11 1110')].call(ops, 0)).toEqual(3); + }); + it('while() with true condition should go to the next line', () => { + const code = [ + h('100011 11 11 1101 000000000000000000'), // while (v3===v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 11 11 1101')].call(ops, 0)).toEqual(1); + }); + it('while() with true at the beginning and false after', () => { + const code = [ + h('100011 00 01 1110 000000000000000000'), // while (v0!==v1) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 00 01 1110')].call(ops, 0)).toEqual(1); + expect(ops.operators[h('100000 00 01')].call(ops, 1)).toEqual(2); + expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(0); + expect(ops.operators[h('100011 00 01 1110')].call(ops, 0)).toEqual(3); + }); }); }); \ No newline at end of file From 9b17e48facacb89f2aad8f548a80bc899cd62f62 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 6 May 2018 15:49:23 +0300 Subject: [PATCH 23/88] added tests for loops #145 --- client/src/vm/OperatorsSpec.js | 80 ++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 24c79d5..1617358 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -33,7 +33,7 @@ describe("client/src/vm/Operators", () => { vars = null; }); - xdescribe('Creation and destroy', () => { + describe('Creation and destroy', () => { it('Checks creation', () => { expect(ops.offs).toEqual(offs); expect(ops.vars).toEqual(vars); @@ -62,7 +62,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('vars 2bits per var', () => { + describe('vars 2bits per var', () => { it('Checks v0=v1', () => { expect(ops.operators[h('100000 00 01')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -145,7 +145,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('consts 2bits per var', () => { + describe('consts 2bits per var', () => { it('Checks v0=1', () => { expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 000000000000000000000'))).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -228,7 +228,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('ifs 2bits per var', () => { + describe('ifs 2bits per var', () => { it('if(v3!==v3) should be false', () => { const code = [ h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { @@ -301,6 +301,14 @@ describe("client/src/vm/Operators", () => { ops.updateIndexes(code); expect(ops.operators[h('100010 11 11 1101')].call(ops, 0)).toEqual(1); }); + it('Garbage in a tail should not affect if', () => { + const code = [ + h('100010 00 00 1101 111111111111111111'), // if (v0===v0) { + h('100000 00 01 1111111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 00 00 1101')].call(ops, 0)).toEqual(1); + }); describe('ifs 3bits per var', () => { let bpv; @@ -399,6 +407,14 @@ describe("client/src/vm/Operators", () => { ops.updateIndexes(code); expect(ops.operators[h('100010 011 011 1101')].call(ops, 0)).toEqual(1); }); + it('Garbage in a tail should not affect if', () => { + const code = [ + h('100010 000 000 1101 1111111111111111'), // if (v0===v0) { + h('100000 000 001 11111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 000 000 1101')].call(ops, 0)).toEqual(1); + }); }); }); @@ -433,5 +449,61 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(0); expect(ops.operators[h('100011 00 01 1110')].call(ops, 0)).toEqual(3); }); + + describe('loops 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('while() with false condition should go outside the closed bracket', () => { + const code = [ + h('100011 011 011 1110 0000000000000000'), // while (v3!==v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 011 011 1110')].call(ops, 0)).toEqual(3); + }); + it('while() with true condition should go to the next line', () => { + const code = [ + h('100011 011 011 1101 0000000000000000'), // while (v3===v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 011 011 1101')].call(ops, 0)).toEqual(1); + }); + it('while() with true at the beginning and false after', () => { + const code = [ + h('100011 000 001 1110 0000000000000000'), // while (v0!==v1) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 000 001 1110')].call(ops, 0)).toEqual(1); + expect(ops.operators[h('100000 000 001')].call(ops, 1)).toEqual(2); + expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(0); + expect(ops.operators[h('100011 000 001 1110')].call(ops, 0)).toEqual(3); + }); + }); }); }); \ No newline at end of file From 3bbb726edd9b4733404912145f61911ed80ed782 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 6 May 2018 17:53:50 +0300 Subject: [PATCH 24/88] added tests for loops #145 --- client/src/vm/OperatorsSpec.js | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 1617358..ef83a54 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -449,6 +449,24 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(0); expect(ops.operators[h('100011 00 01 1110')].call(ops, 0)).toEqual(3); }); + it('Garbage in a tail of command should not affect values', () => { + const code = [ + h('100011 11 11 1110 111111111111111111'), // while (v3!==v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 11111111111111111111111111') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 11 11 1110')].call(ops, 0)).toEqual(3); + }); + it('Garbage in a tail of command should not affect values 2', () => { + const code = [ + h('100011 11 11 1101 111111111111111111'), // while (v3===v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 11111111111111111111111111') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 11 11 1101')].call(ops, 0)).toEqual(1); + }); describe('loops 3bits per var', () => { let bpv; @@ -504,6 +522,24 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(0); expect(ops.operators[h('100011 000 001 1110')].call(ops, 0)).toEqual(3); }); + it('Garbage in a tail of command should not affect values', () => { + const code = [ + h('100011 011 011 1110 1111111111111111'), // while (v3!==v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 11111111111111111111111111') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 011 011 1110')].call(ops, 0)).toEqual(3); + }); + it('Garbage in a tail of command should not affect values 2', () => { + const code = [ + h('100011 011 011 1101 1111111111111111'), // while (v3===v3) { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 11111111111111111111111111') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100011 011 011 1101')].call(ops, 0)).toEqual(1); + }); }); }); }); \ No newline at end of file From 84cfbcffc94c3d2f1a46be3d9116f06f7097e83a Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 7 May 2018 16:41:14 +0300 Subject: [PATCH 25/88] added tests for operators #145 --- client/src/vm/OperatorsSpec.js | 91 +++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index ef83a54..ad9fde2 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -3,7 +3,8 @@ const OConfig = require('./../manager/plugins/organisms/Config'); const Helper = require('./../../../common/src/Helper'); describe("client/src/vm/Operators", () => { - const h = Helper.toHexNum; + const h = Helper.toHexNum; + const MAX_NUM = Number.MAX_VALUE; let cbpv; let ccb; let ops; @@ -542,4 +543,92 @@ describe("client/src/vm/Operators", () => { }); }); }); + + describe('operators 2bits per var', () => { + it('Checks + operator', () => { + expect(ops.operators[h('100100 00 01 10 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([3,1,2,3]); + }); + it('Checks + operator', () => { + ops.vars[1] = ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 00 01 10 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([MAX_NUM,MAX_NUM,MAX_NUM,3]); + }); + it('Checks + operator', () => { + ops.vars[1] = ops.vars[2] = 0; + expect(ops.operators[h('100100 00 01 10 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([0,0,0,3]); + }); + it('Checks + operator', () => { + ops.vars[1] = ops.vars[2] = -1; + expect(ops.operators[h('100100 00 01 10 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([-2,-1,-1,3]); + }); + it('Checks - operator', () => { + expect(ops.operators[h('100100 00 01 10 0001')].call(ops, 0)).toEqual(1); // v0 = v1 - v2 + expect(ops.vars).toEqual([-1,1,2,3]); + }); + it('Checks - operator', () => { + ops.vars[1] = ops.vars[2] = -1; + expect(ops.operators[h('100100 00 01 10 0001')].call(ops, 0)).toEqual(1); // v0 = v1 - v2 + expect(ops.vars).toEqual([0,-1,-1,3]); + }); + it('Checks - operator', () => { + ops.vars[1] = -MAX_NUM; + ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 00 01 10 0001')].call(ops, 0)).toEqual(1); // v0 = v1 - v2 + expect(ops.vars).toEqual([-MAX_NUM,-MAX_NUM,MAX_NUM,3]); + }); + it('Checks * operator', () => { + expect(ops.operators[h('100100 00 01 10 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([2,1,2,3]); + }); + it('Checks * operator', () => { + ops.vars[1] = ops.vars[2] = -1; + expect(ops.operators[h('100100 00 01 10 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([1,-1,-1,3]); + }); + it('Checks * operator', () => { + ops.vars[1] = -1; + expect(ops.operators[h('100100 00 01 10 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([-2,-1,2,3]); + }); + it('Checks * operator', () => { + ops.vars[1] = ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 00 01 10 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([MAX_NUM,MAX_NUM,MAX_NUM,3]); + }); + it('Checks * operator', () => { + ops.vars[1] = MAX_NUM; + ops.vars[2] = -MAX_NUM; + expect(ops.operators[h('100100 00 01 10 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([MAX_NUM,MAX_NUM,-MAX_NUM,3]); + }); + it('Checks / operator', () => { + expect(ops.operators[h('100100 00 01 10 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([.5,1,2,3]); + }); + it('Checks / operator', () => { + ops.vars[1] = 1; + ops.vars[2] = -1; + expect(ops.operators[h('100100 00 01 10 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([-1,1,-1,3]); + }); + it('Checks / operator', () => { + ops.vars[1] = -1; + ops.vars[2] = -1; + expect(ops.operators[h('100100 00 01 10 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([1,-1,-1,3]); + }); + it('Checks / operator', () => { + ops.vars[1] = -MAX_NUM; + ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 00 01 10 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([-1,-MAX_NUM,MAX_NUM,3]); + }); + it('Checks / operator', () => { + expect(ops.operators[h('100100 01 10 00 0011')].call(ops, 0)).toEqual(1); // v1 = v2 / v0 + expect(ops.vars).toEqual([0,MAX_NUM,2,3]); + }); + }); }); \ No newline at end of file From 4ec0408f4b768bf30b7f9455f0e2cea426fcf75e Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 7 May 2018 17:11:45 +0300 Subject: [PATCH 26/88] added tests for operators #145 --- client/src/vm/OperatorsSpec.js | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index ad9fde2..33bc19b 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -630,5 +630,40 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100100 01 10 00 0011')].call(ops, 0)).toEqual(1); // v1 = v2 / v0 expect(ops.vars).toEqual([0,MAX_NUM,2,3]); }); + it('Checks % operator', () => { + expect(ops.operators[h('100100 00 01 10 0100')].call(ops, 0)).toEqual(1); // v0 = v1 % v2 + expect(ops.vars).toEqual([1,1,2,3]); + }); + it('Checks % operator', () => { + ops.vars[2] = 0; + expect(ops.operators[h('100100 00 01 10 0100')].call(ops, 0)).toEqual(1); // v0 = v1 % v2 + expect(ops.vars).toEqual([0,1,0,3]); + }); + it('Checks & operator', () => { + expect(ops.operators[h('100100 00 01 10 0101')].call(ops, 0)).toEqual(1); // v0 = v1 & v2 + expect(ops.vars).toEqual([0,1,2,3]); + }); + it('Checks & operator', () => { + expect(ops.operators[h('100100 10 01 00 0101')].call(ops, 0)).toEqual(1); // v2 = v1 & v0 + expect(ops.vars).toEqual([0,1,0,3]); + }); + it('Checks & operator', () => { + expect(ops.operators[h('100100 10 01 01 0101')].call(ops, 0)).toEqual(1); // v2 = v1 & v1 + expect(ops.vars).toEqual([0,1,1,3]); + }); + it('Checks < operator', () => { + expect(ops.operators[h('100100 10 01 01 1011')].call(ops, 0)).toEqual(1); // v2 = v1 < v1 + expect(ops.vars).toEqual([0,1,0,3]); + }); + it('Checks < operator', () => { + expect(ops.operators[h('100100 00 01 10 1011')].call(ops, 0)).toEqual(1); // v0 = v1 < v2 + expect(ops.vars).toEqual([1,1,2,3]); + }); + it('Checks < operator', () => { + ops.vars[1] = -1; + ops.vars[2] = -2; + expect(ops.operators[h('100100 00 01 10 1011')].call(ops, 0)).toEqual(1); // v0 = v1 < v2 + expect(ops.vars).toEqual([0,-1,-2,3]); + }); }); }); \ No newline at end of file From f535f4e44a44aa58c39311a38aa7d579df8a8c10 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 9 May 2018 12:35:36 +0300 Subject: [PATCH 27/88] added tests for func declaration and func call #145 --- client/src/vm/Operators.js | 19 +- client/src/vm/OperatorsSpec.js | 348 ++++++++++++++++++++++++++++++++- 2 files changed, 352 insertions(+), 15 deletions(-) diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 13baa1e..2c6ee4c 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -28,7 +28,7 @@ class Operators { */ this.FOUR_BITS = 4; this.CONDITION_BITS = 4; - this.FUNC_NAME_BITS = 10; + this.FUNC_NAME_BITS = 8; /** * {Array} Available conditions for if operator */ @@ -249,11 +249,11 @@ class Operators { * Compiles all variants of function operator and stores they in * this._compiledOperators map. 'xx' means, that amount of bits * depends on configuration. '...' means, that all other bits are - * ignored. Function name consists of 10 bits. Example: + * ignored. Function name(index) consists of 8 bits. Example: * - * bits : 6 10 - * number: 100101 0000000001... - * string: func n + * bits : 6 + * number: 100101... + * string: func */ static _compileFunc() { const ops = this._compiledOperators; @@ -271,8 +271,8 @@ class Operators { * used as function name. If 1 then hard coded functions name will be * get from byte-code. Function name consists of 10 bits. Example: * - * bits : 6 1 10 - * number: 100110 0 0000000001... + * bits : 6 1 8 + * number: 100110 1 00000001... * string: call v1 */ static _compileFuncCall() { @@ -286,7 +286,7 @@ class Operators { eval(`Operators.global.fn = function call(line, num, org) { const data = num << ${opBits}; - const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data >>> ${fnBits}]; + const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data << 1 >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data << 1 >>> ${fnBits}]; if (typeof offs !== 'undefined') { if (this.stack.length > ${MAX_STACK_SIZE} * 3) { org.energy -= org.vm.size; @@ -453,6 +453,7 @@ class Operators { const offs = this.offs; const funcs = this.funcs = new Array(this._MAX_FUNC_AMOUNT); const blocks = []; + let func = 0; this.stack = []; for (let i = 0; i < len; i++) { @@ -464,7 +465,7 @@ class Operators { } if (operator === 0x5) { // func offs[i] = i; - funcs.push(i + 1); + funcs[func++] = i + 1; blocks.push(i); continue; } diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 33bc19b..658381f 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -34,7 +34,7 @@ describe("client/src/vm/Operators", () => { vars = null; }); - describe('Creation and destroy', () => { + xdescribe('Creation and destroy', () => { it('Checks creation', () => { expect(ops.offs).toEqual(offs); expect(ops.vars).toEqual(vars); @@ -63,7 +63,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('vars 2bits per var', () => { + xdescribe('vars 2bits per var', () => { it('Checks v0=v1', () => { expect(ops.operators[h('100000 00 01')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -146,7 +146,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('consts 2bits per var', () => { + xdescribe('consts 2bits per var', () => { it('Checks v0=1', () => { expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 000000000000000000000'))).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -229,7 +229,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('ifs 2bits per var', () => { + xdescribe('ifs 2bits per var', () => { it('if(v3!==v3) should be false', () => { const code = [ h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { @@ -419,7 +419,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('loops 2bits per var', () => { + xdescribe('loops 2bits per var', () => { it('while() with false condition should go outside the closed bracket', () => { const code = [ h('100011 11 11 1110 000000000000000000'), // while (v3!==v3) { @@ -544,7 +544,7 @@ describe("client/src/vm/Operators", () => { }); }); - describe('operators 2bits per var', () => { + xdescribe('operators 2bits per var', () => { it('Checks + operator', () => { expect(ops.operators[h('100100 00 01 10 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 expect(ops.vars).toEqual([3,1,2,3]); @@ -665,5 +665,341 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100100 00 01 10 1011')].call(ops, 0)).toEqual(1); // v0 = v1 < v2 expect(ops.vars).toEqual([0,-1,-2,3]); }); + + describe('operators 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Checks + operator', () => { + expect(ops.operators[h('100100 000 001 010 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([3,1,2,3,4,5,6,7]); + }); + it('Checks + operator', () => { + ops.vars[1] = ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 000 001 010 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([MAX_NUM, MAX_NUM, MAX_NUM, 3,4,5,6,7]); + }); + it('Checks + operator', () => { + ops.vars[1] = ops.vars[2] = 0; + expect(ops.operators[h('100100 000 001 010 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([0, 0, 0, 3,4,5,6,7]); + }); + it('Checks + operator', () => { + ops.vars[1] = ops.vars[2] = -1; + expect(ops.operators[h('100100 000 001 010 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 + expect(ops.vars).toEqual([-2, -1, -1, 3,4,5,6,7]); + }); + it('Checks - operator', () => { + expect(ops.operators[h('100100 000 001 010 0001')].call(ops, 0)).toEqual(1); // v0 = v1 - v2 + expect(ops.vars).toEqual([-1, 1, 2, 3,4,5,6,7]); + }); + it('Checks - operator', () => { + ops.vars[1] = ops.vars[2] = -1; + expect(ops.operators[h('100100 000 001 010 0001')].call(ops, 0)).toEqual(1); // v0 = v1 - v2 + expect(ops.vars).toEqual([0, -1, -1, 3,4,5,6,7]); + }); + it('Checks - operator', () => { + ops.vars[1] = -MAX_NUM; + ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 000 001 010 0001')].call(ops, 0)).toEqual(1); // v0 = v1 - v2 + expect(ops.vars).toEqual([-MAX_NUM, -MAX_NUM, MAX_NUM, 3,4,5,6,7]); + }); + it('Checks * operator', () => { + expect(ops.operators[h('100100 000 001 010 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([2, 1, 2, 3,4,5,6,7]); + }); + it('Checks * operator', () => { + ops.vars[1] = ops.vars[2] = -1; + expect(ops.operators[h('100100 000 001 010 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([1, -1, -1, 3,4,5,6,7]); + }); + it('Checks * operator', () => { + ops.vars[1] = -1; + expect(ops.operators[h('100100 000 001 010 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([-2, -1, 2, 3,4,5,6,7]); + }); + it('Checks * operator', () => { + ops.vars[1] = ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 000 001 010 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([MAX_NUM, MAX_NUM, MAX_NUM, 3,4,5,6,7]); + }); + it('Checks * operator', () => { + ops.vars[1] = MAX_NUM; + ops.vars[2] = -MAX_NUM; + expect(ops.operators[h('100100 000 001 010 0010')].call(ops, 0)).toEqual(1); // v0 = v1 * v2 + expect(ops.vars).toEqual([MAX_NUM, MAX_NUM, -MAX_NUM, 3,4,5,6,7]); + }); + it('Checks / operator', () => { + expect(ops.operators[h('100100 000 001 010 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([.5, 1, 2, 3,4,5,6,7]); + }); + it('Checks / operator', () => { + ops.vars[1] = 1; + ops.vars[2] = -1; + expect(ops.operators[h('100100 000 001 010 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([-1, 1, -1, 3,4,5,6,7]); + }); + it('Checks / operator', () => { + ops.vars[1] = -1; + ops.vars[2] = -1; + expect(ops.operators[h('100100 000 001 010 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([1, -1, -1, 3,4,5,6,7]); + }); + it('Checks / operator', () => { + ops.vars[1] = -MAX_NUM; + ops.vars[2] = MAX_NUM; + expect(ops.operators[h('100100 000 001 010 0011')].call(ops, 0)).toEqual(1); // v0 = v1 / v2 + expect(ops.vars).toEqual([-1, -MAX_NUM, MAX_NUM, 3,4,5,6,7]); + }); + it('Checks / operator', () => { + expect(ops.operators[h('100100 001 010 000 0011')].call(ops, 0)).toEqual(1); // v1 = v2 / v0 + expect(ops.vars).toEqual([0, MAX_NUM, 2, 3,4,5,6,7]); + }); + it('Checks % operator', () => { + expect(ops.operators[h('100100 000 001 010 0100')].call(ops, 0)).toEqual(1); // v0 = v1 % v2 + expect(ops.vars).toEqual([1, 1, 2, 3,4,5,6,7]); + }); + it('Checks % operator', () => { + ops.vars[2] = 0; + expect(ops.operators[h('100100 000 001 010 0100')].call(ops, 0)).toEqual(1); // v0 = v1 % v2 + expect(ops.vars).toEqual([0, 1, 0, 3,4,5,6,7]); + }); + it('Checks & operator', () => { + expect(ops.operators[h('100100 000 001 010 0101')].call(ops, 0)).toEqual(1); // v0 = v1 & v2 + expect(ops.vars).toEqual([0, 1, 2, 3,4,5,6,7]); + }); + it('Checks & operator', () => { + expect(ops.operators[h('100100 010 001 000 0101')].call(ops, 0)).toEqual(1); // v2 = v1 & v0 + expect(ops.vars).toEqual([0, 1, 0, 3,4,5,6,7]); + }); + it('Checks & operator', () => { + expect(ops.operators[h('100100 010 001 001 0101')].call(ops, 0)).toEqual(1); // v2 = v1 & v1 + expect(ops.vars).toEqual([0, 1, 1, 3,4,5,6,7]); + }); + it('Checks < operator', () => { + expect(ops.operators[h('100100 010 001 001 1011')].call(ops, 0)).toEqual(1); // v2 = v1 < v1 + expect(ops.vars).toEqual([0, 1, 0, 3,4,5,6,7]); + }); + it('Checks < operator', () => { + expect(ops.operators[h('100100 000 001 010 1011')].call(ops, 0)).toEqual(1); // v0 = v1 < v2 + expect(ops.vars).toEqual([1, 1, 2, 3,4,5,6,7]); + }); + it('Checks < operator', () => { + ops.vars[1] = -1; + ops.vars[2] = -2; + expect(ops.operators[h('100100 000 001 010 1011')].call(ops, 0)).toEqual(1); // v0 = v1 < v2 + expect(ops.vars).toEqual([0, -1, -2, 3,4,5,6,7]); + }); + }); + }); + + xdescribe('function declaration 2bits per var', () => { + it('Func declaration should be skipped during run', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1() { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + }); + it('Two func declaration should be skipped during run', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('100101 00000001 000000000000000000'), // func 2() { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + expect(ops.operators[h('100101')].call(ops, 3)).toEqual(6); + }); + it('func inside func should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100101 00000001 000000000000000000'), // func 2 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(4); + }); + it('func without closed bracket should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100000 00 01 1111111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); + }); + it('one line func should work', () => { + const code = [ + h('100101 00000001 000000000000000000') // func 1 { + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); + }); + it('func with two closed brackets should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(2); + }); + it('func with two closed brackets should work', () => { + const code = [ + h('101000 00000000000000000000000000'), // } + h('100101 00000001 000000000000000000'), // func 1 { + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + }); + }); + + xdescribe('function declaration 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Func declaration should be skipped during run', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1() { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + }); + it('Two func declaration should be skipped during run', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('100101 00000001 000000000000000000'), // func 2() { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + expect(ops.operators[h('100101')].call(ops, 3)).toEqual(6); + }); + it('func inside func should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100101 00000001 000000000000000000'), // func 2 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(4); + }); + it('func without closed bracket should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100000 000 001 11111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); + }); + it('one line func should work', () => { + const code = [ + h('100101 00000001 000000000000000000') // func 1 { + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); + }); + it('func with two closed brackets should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(2); + }); + it('func with two closed brackets should work', () => { + const code = [ + h('101000 00000000000000000000000000'), // } + h('100101 00000001 000000000000000000'), // func 1 { + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + }); + }); + + describe('function call 2bits per var', () => { + it('Func call should work', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0() { + h('101000 00000000000000000000000000'), // } + h('100110 1 00000000 00000000000000000') // call 0() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(2); + expect(ops.operators[h('100110')].call(ops, 2, code[2], {}, code)).toEqual(1); + expect(ops.operators[h('101000')].call(ops, 1, code[1], {}, code)).toEqual(3); + }); + it('Vars within function should not affect outside vars', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0() { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('100110 1 00000000 00000000000000000') // call 0() + ]; + ops.updateIndexes(code); + expect(ops.vars).toEqual([0,1,2,3]); + expect(ops.operators[h('100110')].call(ops, 3, code[3], {}, code)).toEqual(1); + expect(ops.operators[h('100000 00 01')].call(ops, 1, code[1], {}, code)).toEqual(2); + expect(ops.vars).toEqual([1,1,2,3]); + expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(4); + expect(ops.vars).toEqual([0,1,2,3]); + }); }); }); \ No newline at end of file From b65be38aa49f60cefdd3f8e70876fe030578644d Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 9 May 2018 13:20:19 +0300 Subject: [PATCH 28/88] added tests for func declaration and func call #145 --- client/src/vm/OperatorsSpec.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 658381f..5ca8f6c 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -1001,5 +1001,17 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(4); expect(ops.vars).toEqual([0,1,2,3]); }); + it('func inside func should be callable', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0 { + h('100101 00000000000000000000000000'), // func 1 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000'), // } + h('100110 1 00000001 00000000000000000') // call 1() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100110')].call(ops, 4, code[4], {}, code)).toEqual(2); + expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(5); + }); }); }); \ No newline at end of file From e25a1dfb1746246fa3bdc720278ee28a929e0033 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 10 May 2018 12:52:15 +0300 Subject: [PATCH 29/88] added tests for return operator #145 --- client/src/vm/Operators.js | 14 ++- client/src/vm/OperatorsSpec.js | 195 ++++++++++++++++++--------------- 2 files changed, 113 insertions(+), 96 deletions(-) diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 2c6ee4c..fc0c14b 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -9,7 +9,7 @@ const Num = require('./Num'); const Helper = require('./../../../common/src/Helper'); const OPERATOR_AMOUNT = 11; -const MAX_STACK_SIZE = 10000; +const MAX_STACK_SIZE = 30000; class Operators { /** @@ -288,7 +288,7 @@ class Operators { const data = num << ${opBits}; const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data << 1 >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data << 1 >>> ${fnBits}]; if (typeof offs !== 'undefined') { - if (this.stack.length > ${MAX_STACK_SIZE} * 3) { + if (this.stack.length > ${MAX_STACK_SIZE}) { org.energy -= org.vm.size; return ++line; } @@ -304,7 +304,8 @@ class Operators { * Compiles all variants of return operator and stores they in * this._compiledOperators map. 'xx' means, that amount of bits * depends on configuration. '...' means, that all other bits are - * ignored. Example: + * ignored. Returns fro custom function. If returns appears outside + * the function, then interpreter jumps into zero line. Example: * * bits : 6 * number: 100111 ... @@ -316,12 +317,13 @@ class Operators { const vars = Math.pow(2, OConfig.codeBitsPerVar); eval(`Operators.global.fn = function ret(line) { - if (this.stack.length > 0) { - const stackVars = this.stack.pop(); + const stack = this.stack; + if (stack.length > 0) { + const stackVars = stack.pop(); const vars = this.vars; for (let i = 0; i < ${vars}; i++) {vars[i] = stackVars[i]} stack.pop(); - return this.stack.pop(); + return stack.pop(); } return 0; }`); diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 5ca8f6c..3916a64 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -880,101 +880,101 @@ describe("client/src/vm/Operators", () => { ops.updateIndexes(code); expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); }); - }); - xdescribe('function declaration 3bits per var', () => { - let bpv; - let ops; - let vars; - let offs; - beforeAll (() => { - bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - Operators.compile(); - }); - afterAll (() => Operators.compile()); - beforeEach(() => { - vars = [0,1,2,3,4,5,6,7]; - offs = new Array(10); - ops = new Operators(offs, vars); - }); - afterEach (() => { - ops.destroy(); - ops = null; - offs = null; - vars = null; - OConfig.codeBitsPerVar = bpv; - }); + xdescribe('function declaration 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + Operators.compile(); + }); + afterAll (() => Operators.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); - it('Func declaration should be skipped during run', () => { - const code = [ - h('100101 00000001 000000000000000000'), // func 1() { - h('100000 000 001 11111111111111111111'), // v0 = v1 - h('101000 00000000000000000000000000') // } - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); - }); - it('Two func declaration should be skipped during run', () => { - const code = [ - h('100101 00000001 000000000000000000'), // func 1 { - h('100000 000 001 11111111111111111111'), // v0 = v1 - h('101000 00000000000000000000000000'), // } - h('100101 00000001 000000000000000000'), // func 2() { - h('100000 000 001 11111111111111111111'), // v0 = v1 - h('101000 00000000000000000000000000') // } - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); - expect(ops.operators[h('100101')].call(ops, 3)).toEqual(6); - }); - it('func inside func should work', () => { - const code = [ - h('100101 00000001 000000000000000000'), // func 1 { - h('100101 00000001 000000000000000000'), // func 2 { - h('101000 00000000000000000000000000'), // } - h('101000 00000000000000000000000000') // } - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(4); - }); - it('func without closed bracket should work', () => { - const code = [ - h('100101 00000001 000000000000000000'), // func 1 { - h('100000 000 001 11111111111111111111') // v0 = v1 - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); - }); - it('one line func should work', () => { - const code = [ - h('100101 00000001 000000000000000000') // func 1 { - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); - }); - it('func with two closed brackets should work', () => { - const code = [ - h('100101 00000001 000000000000000000'), // func 1 { - h('101000 00000000000000000000000000'), // } - h('101000 00000000000000000000000000') // } - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(2); - }); - it('func with two closed brackets should work', () => { - const code = [ - h('101000 00000000000000000000000000'), // } - h('100101 00000001 000000000000000000'), // func 1 { - h('101000 00000000000000000000000000') // } - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + it('Func declaration should be skipped during run', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1() { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + }); + it('Two func declaration should be skipped during run', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('100101 00000001 000000000000000000'), // func 2() { + h('100000 000 001 11111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + expect(ops.operators[h('100101')].call(ops, 3)).toEqual(6); + }); + it('func inside func should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100101 00000001 000000000000000000'), // func 2 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(4); + }); + it('func without closed bracket should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('100000 000 001 11111111111111111111') // v0 = v1 + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); + }); + it('one line func should work', () => { + const code = [ + h('100101 00000001 000000000000000000') // func 1 { + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(1); + }); + it('func with two closed brackets should work', () => { + const code = [ + h('100101 00000001 000000000000000000'), // func 1 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(2); + }); + it('func with two closed brackets should work', () => { + const code = [ + h('101000 00000000000000000000000000'), // } + h('100101 00000001 000000000000000000'), // func 1 { + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); + }); }); }); - describe('function call 2bits per var', () => { + xdescribe('function call', () => { it('Func call should work', () => { const code = [ h('100101 00000000000000000000000000'), // func 0() { @@ -1014,4 +1014,19 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(5); }); }); + + describe('return', () => { + it('Func call should work', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0() { + h('100111 00000000000000000000000000'), // return + h('101000 00000000000000000000000000'), // } + h('100110 1 00000000 00000000000000000') // call 0() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + expect(ops.operators[h('100110')].call(ops, 3, code[3], {}, code)).toEqual(1); + expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(4); + }); + }); }); \ No newline at end of file From cf3befada48bcc3d6444721d3578d65c1af7bec0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 10 May 2018 14:01:34 +0300 Subject: [PATCH 30/88] added tests for return operator #145 --- client/src/vm/OperatorsSpec.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 3916a64..e8d6ef0 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -1028,5 +1028,12 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100110')].call(ops, 3, code[3], {}, code)).toEqual(1); expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(4); }); + it('Func call should work', () => { + const code = [ + h('100111 00000000000000000000000000') // return + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100111')].call(ops, 0)).toEqual(0); + }); }); }); \ No newline at end of file From 76dc434368c2dbdd2afe49e357b34754accc97b5 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 10 May 2018 14:28:50 +0300 Subject: [PATCH 31/88] added tests for return operator #145 --- client/src/vm/OperatorsSpec.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index e8d6ef0..bc0c531 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -34,7 +34,7 @@ describe("client/src/vm/Operators", () => { vars = null; }); - xdescribe('Creation and destroy', () => { + describe('Creation and destroy', () => { it('Checks creation', () => { expect(ops.offs).toEqual(offs); expect(ops.vars).toEqual(vars); @@ -63,7 +63,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('vars 2bits per var', () => { + describe('vars 2bits per var', () => { it('Checks v0=v1', () => { expect(ops.operators[h('100000 00 01')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -146,7 +146,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('consts 2bits per var', () => { + describe('consts 2bits per var', () => { it('Checks v0=1', () => { expect(ops.operators[h('100001 00')].call(ops, 0, h('100001 00 001 000000000000000000000'))).toEqual(1); expect(ops.vars).toEqual([1,1,2,3]); @@ -229,7 +229,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('ifs 2bits per var', () => { + describe('ifs 2bits per var', () => { it('if(v3!==v3) should be false', () => { const code = [ h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { @@ -419,7 +419,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('loops 2bits per var', () => { + describe('loops 2bits per var', () => { it('while() with false condition should go outside the closed bracket', () => { const code = [ h('100011 11 11 1110 000000000000000000'), // while (v3!==v3) { @@ -544,7 +544,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('operators 2bits per var', () => { + describe('operators 2bits per var', () => { it('Checks + operator', () => { expect(ops.operators[h('100100 00 01 10 0000')].call(ops, 0)).toEqual(1); // v0 = v1 + v2 expect(ops.vars).toEqual([3,1,2,3]); @@ -813,7 +813,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('function declaration 2bits per var', () => { + describe('function declaration 2bits per var', () => { it('Func declaration should be skipped during run', () => { const code = [ h('100101 00000001 000000000000000000'), // func 1() { @@ -974,7 +974,7 @@ describe("client/src/vm/Operators", () => { }); }); - xdescribe('function call', () => { + describe('function call', () => { it('Func call should work', () => { const code = [ h('100101 00000000000000000000000000'), // func 0() { @@ -1016,7 +1016,7 @@ describe("client/src/vm/Operators", () => { }); describe('return', () => { - it('Func call should work', () => { + it('return inside func should jump outside of it', () => { const code = [ h('100101 00000000000000000000000000'), // func 0() { h('100111 00000000000000000000000000'), // return @@ -1028,12 +1028,20 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100110')].call(ops, 3, code[3], {}, code)).toEqual(1); expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(4); }); - it('Func call should work', () => { + it('One return should create infinite loop', () => { const code = [ h('100111 00000000000000000000000000') // return ]; ops.updateIndexes(code); expect(ops.operators[h('100111')].call(ops, 0)).toEqual(0); }); + it('return outside the func should jump to zero line', () => { + const code = [ + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('100111 11111111111111111111111111') // return + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100111')].call(ops, 1)).toEqual(0); + }); }); }); \ No newline at end of file From 0f1e311e967ba4a10a8cc1217cfd851106b1f494 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 10 May 2018 20:09:25 +0300 Subject: [PATCH 32/88] added tests for return/call func operators #145 --- client/src/vm/Operators.js | 4 ++-- client/src/vm/OperatorsSpec.js | 40 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index fc0c14b..701d742 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -281,12 +281,12 @@ class Operators { const ifBit = Num.MAX_BITS - 1; const fnBits = Num.MAX_BITS - this.FUNC_NAME_BITS; const funcs = Math.pow(2, this.FUNC_NAME_BITS); - const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar - 1; + const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar; const opBits = Num.BITS_PER_OPERATOR; eval(`Operators.global.fn = function call(line, num, org) { const data = num << ${opBits}; - const offs = this.funcs[(data >>> ${ifBit}) & 1 === 0 ? ((this.vars[data << 1 >>> ${varBits}] + .5) << 0 >>> 0) % ${funcs} : data << 1 >>> ${fnBits}]; + const offs = this.funcs[data >>> ${ifBit} === 0 ? Math.round(this.vars[data << 1 >>> ${varBits}]) % ${funcs} : data << 1 >>> ${fnBits}]; if (typeof offs !== 'undefined') { if (this.stack.length > ${MAX_STACK_SIZE}) { org.energy -= org.vm.size; diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index bc0c531..9b6ec3f 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -1013,6 +1013,18 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100110')].call(ops, 4, code[4], {}, code)).toEqual(2); expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(5); }); + it('func should be callable through var', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0 { + h('100101 00000000000000000000000000'), // func 1 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000'), // } + h('100110 0 01 00000000000000000000000') // call v1() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100110')].call(ops, 4, code[4], {}, code)).toEqual(2); + expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(5); + }); }); describe('return', () => { @@ -1044,4 +1056,32 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100111')].call(ops, 1)).toEqual(0); }); }); + + describe('return', () => { + it('return inside func should jump outside of it', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0() { + h('100111 00000000000000000000000000'), // return + h('101000 00000000000000000000000000'), // } + h('100110 1 00000000 00000000000000000') // call 0() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); + expect(ops.operators[h('100110')].call(ops, 3, code[3], {}, code)).toEqual(1); + expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(4); + }); + it('func inside func should be callable', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0 { + h('100101 00000000000000000000000000'), // func 1 { + h('100111 00000000000000000000000000'), // return + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000'), // } + h('100110 1 00000001 00000000000000000') // call 1() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100110')].call(ops, 5, code[5], {}, code)).toEqual(2); + expect(ops.operators[h('100111')].call(ops, 2, code[2], {}, code)).toEqual(6); + }); + }); }); \ No newline at end of file From 53817c338206860502d83e2acf5c6b334beb08c0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 10 May 2018 23:12:08 +0300 Subject: [PATCH 33/88] added tests for return operator #145 --- client/src/vm/OperatorsSpec.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 9b6ec3f..e44fe44 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -1025,6 +1025,17 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100110')].call(ops, 4, code[4], {}, code)).toEqual(2); expect(ops.operators[h('101000')].call(ops, 2, code[2], {}, code)).toEqual(5); }); + it('undefined func should not be callable through var', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0 { + h('100101 00000000000000000000000000'), // func 1 { + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000'), // } + h('100110 0 10 00000000000000000000000') // call v1() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100110')].call(ops, 4, code[4], {}, code)).toEqual(5); + }); }); describe('return', () => { @@ -1083,5 +1094,18 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100110')].call(ops, 5, code[5], {}, code)).toEqual(2); expect(ops.operators[h('100111')].call(ops, 2, code[2], {}, code)).toEqual(6); }); + it('Two return inside func should jump outside of it', () => { + const code = [ + h('100101 00000000000000000000000000'), // func 0() { + h('100111 00000000000000000000000000'), // return + h('100111 00000000000000000000000000'), // return + h('101000 00000000000000000000000000'), // } + h('100110 1 00000000 00000000000000000') // call 0() + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100101')].call(ops, 0)).toEqual(4); + expect(ops.operators[h('100110')].call(ops, 4, code[4], {}, code)).toEqual(1); + expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(5); + }); }); }); \ No newline at end of file From f9d9beabae4f730658f36cd6a711901feca0b456 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 11 May 2018 18:15:02 +0300 Subject: [PATCH 34/88] added tests for bracket and toMem operators #145 --- client/src/vm/OperatorsSpec.js | 57 +++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index e44fe44..f1d8039 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -1039,18 +1039,6 @@ describe("client/src/vm/Operators", () => { }); describe('return', () => { - it('return inside func should jump outside of it', () => { - const code = [ - h('100101 00000000000000000000000000'), // func 0() { - h('100111 00000000000000000000000000'), // return - h('101000 00000000000000000000000000'), // } - h('100110 1 00000000 00000000000000000') // call 0() - ]; - ops.updateIndexes(code); - expect(ops.operators[h('100101')].call(ops, 0)).toEqual(3); - expect(ops.operators[h('100110')].call(ops, 3, code[3], {}, code)).toEqual(1); - expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(4); - }); it('One return should create infinite loop', () => { const code = [ h('100111 00000000000000000000000000') // return @@ -1066,9 +1054,6 @@ describe("client/src/vm/Operators", () => { ops.updateIndexes(code); expect(ops.operators[h('100111')].call(ops, 1)).toEqual(0); }); - }); - - describe('return', () => { it('return inside func should jump outside of it', () => { const code = [ h('100101 00000000000000000000000000'), // func 0() { @@ -1108,4 +1093,46 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100111')].call(ops, 1, code[1], {}, code)).toEqual(5); }); }); + + describe('bracket', () => { + it('Script of one bracket should work', () => { + const code = [ + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('101000')].call(ops, 0)).toEqual(1); + }); + it('Script of two brackets should work', () => { + const code = [ + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('101000')].call(ops, 0)).toEqual(1); + expect(ops.operators[h('101000')].call(ops, 1)).toEqual(2); + }); + it('if(v3!==v3) should be false', () => { + const code = [ + h('100010 11 11 1110 000000000000000000'), // if (v3!==v3) { + h('100000 00 01 1111111111111111111111'), // v0 = v1 + h('101000 00000000000000000000000000'), // } + h('101000 00000000000000000000000000') // } + ]; + ops.updateIndexes(code); + expect(ops.operators[h('100010 11 11 1110')].call(ops, 0)).toEqual(3); + expect(ops.operators[h('101000')].call(ops, 3)).toEqual(4); + }); + }); + + describe('toMem 2bits per var', () => { + it('Script of one bracket should work', () => { + const code = [ + h('101001 00 01 0000000000000000000000') // toMem(v0, v1) + ]; + const org = {mem: [0,1,2,3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101001 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([1,1,2,3]); + }); + }); }); \ No newline at end of file From 0a1e607f674c90b32c58f5f28307a4fbd9579651 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 12 May 2018 22:22:11 +0300 Subject: [PATCH 35/88] added tests for toMem/fromMem operators #145 --- client/src/vm/OperatorsSpec.js | 175 ++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 2 deletions(-) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index f1d8039..8b31c38 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -881,7 +881,7 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('100101')].call(ops, 1)).toEqual(3); }); - xdescribe('function declaration 3bits per var', () => { + describe('function declaration 3bits per var', () => { let bpv; let ops; let vars; @@ -1125,7 +1125,17 @@ describe("client/src/vm/Operators", () => { }); describe('toMem 2bits per var', () => { - it('Script of one bracket should work', () => { + const memBits = OConfig.orgMemBits; + beforeAll(() => { + OConfig.orgMemBits = 2; + Operators.compile(); + }); + afterAll (() => { + OConfig.orgMemBits = memBits; + Operators.compile(); + }); + + it('toMem operator should work', () => { const code = [ h('101001 00 01 0000000000000000000000') // toMem(v0, v1) ]; @@ -1134,5 +1144,166 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101001 00 01')].call(ops, 0, code[0], org)).toEqual(1); expect(org.mem).toEqual([1,1,2,3]); }); + it('toMem operator should work 2', () => { + const code = [ + h('101001 00 00 0000000000000000000000') // toMem(v0, v0) + ]; + const org = {mem: [0,1,2,3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101001 00 00')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,3]); + }); + it('Garbage in a tail should not affect toMem operator', () => { + const code = [ + h('101001 00 00 1111111111111111111111') // toMem(v0, v0) + ]; + const org = {mem: [0,1,2,3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101001 00 00')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,3]); + }); + it('toMem operator should have offset limit', () => { + const code = [ + h('101001 00 01 0000000000000000000000') // toMem(v0, v1) + ]; + const org = {mem: [0,1,2,3]}; + ops.vars[0] = 100; + ops.updateIndexes(code); + expect(ops.operators[h('101001 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,1]); + }); + it('toMem operator should have offset limit (minus value)', () => { + const code = [ + h('101001 00 01 0000000000000000000000') // toMem(v0, v1) + ]; + const org = {mem: [0,1,2,3]}; + ops.vars[0] = -10; + ops.vars[1] = -1; + ops.updateIndexes(code); + expect(ops.operators[h('101001 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,-1]); + }); + + describe('toMem 3bits per var', () => { + let memBits; + let bpv; + let ops; + let vars; + let offs; + + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + memBits = OConfig.orgMemBits; + OConfig.codeBitsPerVar = 3; + OConfig.orgMemBits = 2; + Operators.compile(); + }); + afterAll (() => { + OConfig.orgMemBits = memBits; + Operators.compile(); + }); + + it('toMem operator should work', () => { + const code = [ + h('101001 000 001 00000000000000000000') // toMem(v0, v1) + ]; + const org = {mem: [0,1,2,3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101001 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([1,1,2,3]); + }); + it('toMem operator should work 2', () => { + const code = [ + h('101001 000 000 00000000000000000000') // toMem(v0, v0) + ]; + const org = {mem: [0,1,2,3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101001 000 000')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,3]); + }); + it('Garbage in a tail should not affect toMem operator', () => { + const code = [ + h('101001 000 000 11111111111111111111') // toMem(v0, v0) + ]; + const org = {mem: [0,1,2,3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101001 000 000')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,3]); + }); + it('toMem operator should have offset limit', () => { + const code = [ + h('101001 000 001 00000000000000000000') // toMem(v0, v1) + ]; + const org = {mem: [0,1,2,3]}; + ops.vars[0] = 100; + ops.updateIndexes(code); + expect(ops.operators[h('101001 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,1]); + }); + it('toMem operator should have offset limit (minus value)', () => { + const code = [ + h('101001 000 001 00000000000000000000') // toMem(v0, v1) + ]; + const org = {mem: [0,1,2,3]}; + ops.vars[0] = -10; + ops.vars[1] = -1; + ops.updateIndexes(code); + expect(ops.operators[h('101001 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(org.mem).toEqual([0,1,2,-1]); + }); + }); + }); + + describe('fromMem 2bits per var', () => { + const memBits = OConfig.orgMemBits; + beforeAll(() => { + OConfig.orgMemBits = 2; + Operators.compile(); + }); + afterAll (() => { + OConfig.orgMemBits = memBits; + Operators.compile(); + }); + + it('fromMem operator should work', () => { + const code = [ + h('101010 00 01 0000000000000000000000') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101010 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3]); + }); + it('fromMem operator should work', () => { + const code = [ + h('101010 01 01 0000000000000000000000') // v1 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101010 01 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 3]); + }); + it('fromMem operator should have offset limit', () => { + const code = [ + h('101010 00 01 0000000000000000000000') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.vars[1] = 100; + ops.updateIndexes(code); + expect(ops.operators[h('101010 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([3, 100, 2, 3]); + }); }); }); \ No newline at end of file From bb466901d78417ee5d35655fa93ba81184bed511 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 12 May 2018 22:26:50 +0300 Subject: [PATCH 36/88] added tests for fromMem operator #145 --- client/src/vm/OperatorsSpec.js | 99 ++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 8b31c38..8fb9d4d 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -1305,5 +1305,104 @@ describe("client/src/vm/Operators", () => { expect(ops.operators[h('101010 00 01')].call(ops, 0, code[0], org)).toEqual(1); expect(ops.vars).toEqual([3, 100, 2, 3]); }); + it('fromMem operator should have offset limit 2', () => { + const code = [ + h('101010 00 01 0000000000000000000000') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.vars[1] = -100; + ops.updateIndexes(code); + expect(ops.operators[h('101010 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([3, -100, 2, 3]); + }); + it('Garbage in a tail should not affect fromMem operator', () => { + const code = [ + h('101010 00 01 1111111111111111111111') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101010 00 01')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3]); + }); + + describe('fromMem 3bits per var', () => { + let memBits; + let bpv; + let ops; + let vars; + let offs; + + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new Operators(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + memBits = OConfig.orgMemBits; + OConfig.codeBitsPerVar = 3; + OConfig.orgMemBits = 2; + Operators.compile(); + }); + afterAll (() => { + OConfig.orgMemBits = memBits; + Operators.compile(); + }); + + it('fromMem operator should work', () => { + const code = [ + h('101010 000 001 00000000000000000000') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101010 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3, 4, 5, 6, 7]); + }); + it('fromMem operator should work', () => { + const code = [ + h('101010 001 001 00000000000000000000') // v1 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101010 001 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + }); + it('fromMem operator should have offset limit', () => { + const code = [ + h('101010 000 001 00000000000000000000') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.vars[1] = 100; + ops.updateIndexes(code); + expect(ops.operators[h('101010 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([3, 100, 2, 3, 4, 5, 6, 7]); + }); + it('fromMem operator should have offset limit 2', () => { + const code = [ + h('101010 000 001 00000000000000000000') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.vars[1] = -100; + ops.updateIndexes(code); + expect(ops.operators[h('101010 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([3, -100, 2, 3, 4, 5, 6, 7]); + }); + it('Garbage in a tail should not affect fromMem operator', () => { + const code = [ + h('101010 000 001 11111111111111111111') // v0 = fromMem(v1) + ]; + const org = {mem: [0, 1, 2, 3]}; + ops.updateIndexes(code); + expect(ops.operators[h('101010 000 001')].call(ops, 0, code[0], org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3, 4, 5, 6, 7]); + }); + }); }); }); \ No newline at end of file From acc7c077a678de828178b14c468f10503f69cce1 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 12 May 2018 22:38:01 +0300 Subject: [PATCH 37/88] added tests for fromMem operator #145 --- .../plugins/organisms/dos/Operators.js | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index f7834d3..656b737 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -89,8 +89,8 @@ class OperatorsDos extends Operators { static _compileLookAt() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -124,7 +124,7 @@ class OperatorsDos extends Operators { this._obs.fire(${EVENTS.STEP}, org, org.x, org.y, org.dirX, org.dirY); return ++line; }`); - this._compiledOperators[this._toHexNum(`${'101100'}`)] = this.global.fn; + this._compiledOperators[Helper.toHexNum(`${'101100'}`)] = this.global.fn; } /** @@ -140,8 +140,8 @@ class OperatorsDos extends Operators { static _compileDir() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); const dirs = OFFSX.length; @@ -167,8 +167,8 @@ class OperatorsDos extends Operators { static _compileMyX() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -193,8 +193,8 @@ class OperatorsDos extends Operators { static _compileMyY() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -219,8 +219,8 @@ class OperatorsDos extends Operators { static _compileEat() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -285,8 +285,8 @@ class OperatorsDos extends Operators { static _compilePut() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); const event = EVENTS.PUT_ENERGY; @@ -331,7 +331,7 @@ class OperatorsDos extends Operators { */ static _compileEnergy() { const ops = this._compiledOperators; - const h = this._toHexNum; + const h = Helper.toHexNum; eval(`Operators.global.fn = function energy(line, num, org) { const poses = this._positions; @@ -392,8 +392,8 @@ class OperatorsDos extends Operators { static _compilePick() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); const dirs = OFFSX.length; @@ -433,8 +433,8 @@ class OperatorsDos extends Operators { static _compileRand() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -461,8 +461,8 @@ class OperatorsDos extends Operators { static _compileSay() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -489,8 +489,8 @@ class OperatorsDos extends Operators { static _compileListen() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -515,8 +515,8 @@ class OperatorsDos extends Operators { static _compileCheck() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -552,8 +552,8 @@ class OperatorsDos extends Operators { static _compileMyEnergy() { const bpv = OConfig.codeBitsPerVar; const ops = this._compiledOperators; - const h = this._toHexNum; - const b = this._toBinStr; + const h = Helper.toHexNum; + const b = Helper.toBinStr; const vars = Math.pow(2, bpv); for (let v0 = 0; v0 < vars; v0++) { @@ -577,7 +577,7 @@ class OperatorsDos extends Operators { */ static _compilePoison() { const ops = this._compiledOperators; - const h = this._toHexNum; + const h = Helper.toHexNum; eval(`Operators.global.fn = function poison(line, num, org) { let x = org.dirX; From 49723ba671746e661048cce4ef47b7694a555a40 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 13 May 2018 21:28:45 +0300 Subject: [PATCH 38/88] added energy objects back to game --- client/src/manager/plugins/energy/Config.js | 2 +- client/src/manager/plugins/objects/Config.js | 16 ++++++++++++---- client/src/manager/plugins/organisms/Config.js | 12 ++++++------ .../manager/plugins/organisms/dos/Operators.js | 4 ++-- client/src/share/Config.js | 2 +- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 3f30fb9..2d905fe 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -37,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [1920 * 2, 1080 * 2, 500, 500] + groups: [1920 * 2, 1080 * 2, 1000, 1000] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index ffa17f4..4686496 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -10,19 +10,27 @@ const Config = { * {Number} An amount of iteration, after which we have to check world energy * objects percent. May be 0 if you want to disable energy objects generation */ - checkPeriod: 6000, + checkPeriod: 4000, /** * {Number} size of one energy objects block in dots */ - blockSize: 10, + blockSize: 4, /** * {Number} Maximum amount of object dots */ - maxValue: 100 * Helper.getColor(8500 + 2 * 500), + maxValue: .1 * Helper.getColor(8500 + 2 * 500) * 4000, /** * {Number} Opposite to maxValue. Minimum amount of object dots */ - minValue: 50 * Helper.getColor(8500 + 2 * 500) + minValue: .05 * Helper.getColor(8500 + 2 * 500) * 4000, + /** + * {Array|null} In case of array you may set sequence of four values: x,y,w,h. + * They means x,y coordinates, width, height of places with high objects concentration. + * Example: assume, that resolution 1920, 1080. [1920 / 2, 1080 / 2, 1920, 1080]. In this + * example all the screen will be filled by objects. As many values by four, you set as + * many places with objects will be created. In case of null, grouping will be disabled. + */ + groups: [1920 * 2, 1080 * 2, 1000, 1000] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 28e979c..4cf04d1 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: [ - .01, .01, .01, .01, .01, // var, const, if, loop, operator, - .001, .001, .001, .001, // func, funcCall, return, bracket - .01, .01, // toMem, fromMem, - .0001, .1, .01, .01, .01, // lookAt, step, dir, myX, myY, - .1, .001, .01, .01, .01, // eat, put, energy, pick, poison, - .01, .0001, .0001, .001, .01 // rand, say, listen, check, myEnergy + .001, .001, .001, .001, .001, // var, const, if, loop, operator, + .0001, .0001, .0001, .0001, // func, funcCall, return, bracket + .001, .001, // toMem, fromMem, + .00001, .1, .001, .001, .001, // lookAt, step, dir, myX, myY, + .1, .0001, .001, .001, .001, // eat, put, energy, pick, poison, + .001, .00001, .00001, .0001, .001 // rand, say, listen, check, myEnergy ], /** * {Array} Probabilities which used, when mutator decides what to do: diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 656b737..bfe846e 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -359,10 +359,10 @@ class OperatorsDos extends Operators { } } - for (let e = 0; e < 5; e++) { + for (let e = 0, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e < len; e++) { if (energy[e].length === 4) { const xy = energy[e]; - const eat = (2**e) * Helper.getColor(EConfig.colorIndex); + const eat = (2**(e+1)) * Helper.getColor(EConfig.colorIndex); if (org.energy + eat <= OConfig.orgMaxEnergy) { org.energy += eat; diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 2b7257d..506ecbc 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -40,7 +40,7 @@ ClientConfig.init({ 'client/Client', 'energy/Energy', 'stones/Stones', - //'objects/Objects', + 'objects/Objects', 'status/console/Console', IS_NODE_JS ? '' : 'status/charts/Charts', 'ips/Ips', From b66ee0e9389be2455d67e23e2895d3af720f5154 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Wed, 16 May 2018 16:30:11 +0300 Subject: [PATCH 39/88] fixed an issue with energy operator (it didn't work) added global config for distribution of organisms within world --- client/src/manager/plugins/energy/Config.js | 10 +++---- client/src/manager/plugins/energy/Energy.js | 26 +------------------ client/src/manager/plugins/objects/Config.js | 8 +++--- client/src/manager/plugins/objects/Objects.js | 4 +-- .../src/manager/plugins/organisms/Config.js | 11 ++++++-- .../manager/plugins/organisms/Organisms.js | 17 +++++++----- .../plugins/organisms/dos/Operators.js | 4 +-- client/src/share/Dots.js | 2 +- client/src/vm/Operators.js | 4 +-- 9 files changed, 36 insertions(+), 50 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 2d905fe..8fde9a6 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -5,7 +5,7 @@ */ const Helper = require('./../../../../../common/src/Helper'); -const ENERGY_COLOR = 10000; +const COLOR_INDEX = 10000; const COLOR = Helper.getColor; const Config = { /** @@ -21,15 +21,15 @@ const Config = { * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS * constant for details */ - colorIndex: ENERGY_COLOR, + colorIndex: COLOR_INDEX, /** * {Number} Maximum amount of energy dots */ - maxValue: .8 * COLOR(ENERGY_COLOR) * 4000, + maxValue: .8 * COLOR(COLOR_INDEX) * 4000, /** * {Number} Opposite to maxValue. Minimum amount of energy dots */ - minValue: .6 * COLOR(ENERGY_COLOR) * 4000, + minValue: .6 * COLOR(COLOR_INDEX) * 4000, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high energy concentration. @@ -37,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [1920 * 2, 1080 * 2, 1000, 1000] + groups: [1920 * 2, 1080 * 2, 2000, 2000] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/energy/Energy.js b/client/src/manager/plugins/energy/Energy.js index 756679e..f799641 100644 --- a/client/src/manager/plugins/energy/Energy.js +++ b/client/src/manager/plugins/energy/Energy.js @@ -5,38 +5,14 @@ */ const Dots = require('./../../../share/Dots'); const EConfig = require('./Config'); -const EVENTS = require('./../../../share/Events').EVENTS; -const Helper = require('./../../../../../common/src/Helper'); class Energy extends Dots { constructor(manager) { super(manager, EConfig, { addOnce : false, compareCb: (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0, - checkMin : (val) => val + this._sharedObj.orgEnergy < this.config.minValue + checkMin : (val) => val + manager.sharedObj.orgEnergy < this.config.minValue }); - this._color = Helper.getColor(EConfig.colorIndex); - this._energy = 0; - this._sharedObj = manager.sharedObj; - } - - onIteration(counter) { - const energy = super.onIteration(counter); - if (energy !== false) { - this.manager.fire(EVENTS.WORLD_ENERGY, (energy + this._sharedObj.orgEnergy) / this._color); - this._energy = energy; - } - } - - /** - * Override of Manager.onLoop() method. Stores amount of energy in sharedObj - * @param {Number} counter Global counter. Time analog - * @param {Number} stamp Time stamp - * @param {Object} sharedObj Shared object of the manager - */ - onLoop(counter, stamp, sharedObj) { - super.onLoop(sharedObj); - sharedObj.energy = this._energy; } } diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index 4686496..141559b 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -3,8 +3,6 @@ * * @author flatline */ -const Helper = require('./../../../../../common/src/Helper'); - const Config = { /** * {Number} An amount of iteration, after which we have to check world energy @@ -18,11 +16,11 @@ const Config = { /** * {Number} Maximum amount of object dots */ - maxValue: .1 * Helper.getColor(8500 + 2 * 500) * 4000, + maxValue: .2 * 0x6d3b4 * 4000, /** * {Number} Opposite to maxValue. Minimum amount of object dots */ - minValue: .05 * Helper.getColor(8500 + 2 * 500) * 4000, + minValue: .1 * 0x6d3b4 * 4000, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high objects concentration. @@ -30,7 +28,7 @@ const Config = { * example all the screen will be filled by objects. As many values by four, you set as * many places with objects will be created. In case of null, grouping will be disabled. */ - groups: [1920 * 2, 1080 * 2, 1000, 1000] + groups: [1920 * 2, 1080 * 2, 50, 50] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js index ff2d4e4..022fdfd 100644 --- a/client/src/manager/plugins/objects/Objects.js +++ b/client/src/manager/plugins/objects/Objects.js @@ -6,7 +6,7 @@ */ const Dots = require('./../../../share/Dots'); const Helper = require('./../../../../../common/src/Helper'); -const Config = require('./Config'); +const OConfig = require('./Config'); const OBJECT_TYPES = require('./../../../view/World').OBJECT_TYPES; // // We have to add object types to global types storage @@ -27,7 +27,7 @@ class Objects extends Dots { } constructor(manager) { - super(manager, Config, { + super(manager, OConfig, { addOnce : false, compareCb : (x, y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 && manager.positions[x][y] <= OBJECT_TYPES.TYPE_ENERGY0, colorCb : ( ) => COLOR_RGB, diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 4cf04d1..a381027 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -104,13 +104,13 @@ const Config = { /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: 1 * 0x6d3b4, + orgMaxEnergy: 0x6d3b4, /** * {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: 1 * 0x6d3b4, + orgStartEnergy: 0x6d3b4, /** * {Number} Amount of energy, that grabs from organism in case of eating poison */ @@ -149,6 +149,13 @@ const Config = { * {Number} Amount of organisms we have to create on program start */ orgStartAmount: 1000, + /** + * {Array} Array of four elements: x,y,width,height. These values means + * position (x,y) and square (width,height) of high density organisms area. + * You may set this value to empty array to create organisms randomly in + * whole world. + */ + orgPosition: [1920 * 2, 1080 * 2, 2000, 2000], /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 722f999..b59782e 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -188,7 +188,7 @@ class Organisms extends Configurable { this._updateCrossover(counter); } - _onLoop(counter, stamp, sharedObj) { + _onLoop() { this._updateCreate(); } @@ -253,14 +253,19 @@ class Organisms extends Configurable { } _createPopulation() { - const world = this.world; + const world = this.world; + const positions = OConfig.orgPosition; + const hasPosition = positions.length > 3; this.reset(); for (let i = 0, len = OConfig.orgStartAmount; i < len; i++) { - //this.createOrg(...world.getFreePos()); - const x = Helper.rand(500) + 1920 * 2 - 250; - const y = Helper.rand(500) + 1080 * 2 - 250; - if (world.isFree(x, y)) {this.createOrg(x, y)} + if (hasPosition) { + const x = Helper.rand(positions[2]) + positions[0] - positions[2] / 2; + const y = Helper.rand(positions[3]) + positions[1] - positions[3] / 2; + if (world.isFree(x, y)) {this.createOrg(x, y)} + } else { + this.createOrg(...world.getFreePos()); + } } Console.info('Population has created'); } diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index bfe846e..aa40d6e 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -336,7 +336,7 @@ class OperatorsDos extends Operators { eval(`Operators.global.fn = function energy(line, num, org) { const poses = this._positions; const world = this._world; - const energy = {0:[], 1:[], 2:[], 3:[], 4:[]}; + const energy = {1:[], 2:[], 3:[], 4:[], 5:[]}; let e = 0; for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { @@ -359,7 +359,7 @@ class OperatorsDos extends Operators { } } - for (let e = 0, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e < len; e++) { + for (let e = 1, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e <= len; e++) { if (energy[e].length === 4) { const xy = energy[e]; const eat = (2**(e+1)) * Helper.getColor(EConfig.colorIndex); diff --git a/client/src/share/Dots.js b/client/src/share/Dots.js index af1583c..d6f8d09 100644 --- a/client/src/share/Dots.js +++ b/client/src/share/Dots.js @@ -64,7 +64,7 @@ class Dots extends Configurable { const dotsValue = this._getDotsValue(cfg.compareCb); if (cfg.checkMin) { - const percent = cfg.checkMin.call(this, dotsValue); + const percent = cfg.checkMin(dotsValue); if (!percent) {return dotsValue} } else if (dotsValue > config.minValue) {return dotsValue} this._addDots(); diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 701d742..b51e2da 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -218,8 +218,8 @@ class Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 6 xx xx xx 4 - * number: 100100 00 01 00 01... + * bits : 6 xx xx xx 4 + * number: 100100 00 01 00 0001... * string: v0 = v1 - v0 */ static _compileOperator() { From 718f4d339c6d94d19d72cf2ef4c441ea95fce7fb Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 19 May 2018 22:03:30 +0300 Subject: [PATCH 40/88] added Code2JS classes operator bits config has moved to the constant section of configuration --- .../src/manager/plugins/organisms/Config.js | 12 +- .../manager/plugins/organisms/dos/Code2JS.js | 64 +++++ .../plugins/organisms/dos/Code2String.js | 255 ------------------ .../plugins/organisms/dos/Operators.js | 2 +- .../plugins/organisms/dos/OperatorsSpec.js | 2 +- .../plugins/organisms/garmin/Code2String.js | 4 +- client/src/share/Config.js | 2 +- client/src/vm/Code2JS.js | 128 +++++++++ client/src/vm/Num.js | 4 +- client/src/vm/NumSpec.js | 7 +- client/src/vm/Operators.js | 25 +- 11 files changed, 220 insertions(+), 285 deletions(-) create mode 100644 client/src/manager/plugins/organisms/dos/Code2JS.js delete mode 100644 client/src/manager/plugins/organisms/dos/Code2String.js create mode 100644 client/src/vm/Code2JS.js diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index a381027..de9a8ba 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -5,10 +5,17 @@ */ const Config = { /** + * @constant * {Number} Max value, which we may use in orgMutationProbs array. We may use * range: [0...ORG_MUTATION_PROBS_MAX_VAL] including these values */ ORG_MUTATION_PROBS_MAX_VAL: 100, + /** + * @constant + * {Number} Amount of bits for storing operator. This is first XX bits + * in a number. Operator is a type of operation. e.g.: var, func, step, if,... + */ + CODE_BITS_PER_OPERATOR: 6, /** * {Array} Array of operators weights in energy equivalent. Every value of this * array is bind to special operator run on VM. The same sequence should be @@ -185,11 +192,6 @@ const Config = { * which this variable may contain. This value shouldn't be less then 2. */ codeBitsPerVar: 3, - /** - * {Number} Amount of bits for storing operator. This is first XX bits - * in a number. - */ - codeBitsPerOperator: 6, /** * {Number} Amount of bits, which stores maximum block length. Under block * length we mean maximum amount of lines in one block like if, for,... diff --git a/client/src/manager/plugins/organisms/dos/Code2JS.js b/client/src/manager/plugins/organisms/dos/Code2JS.js new file mode 100644 index 0000000..35fdeea --- /dev/null +++ b/client/src/manager/plugins/organisms/dos/Code2JS.js @@ -0,0 +1,64 @@ +/** + * This class is used only for code visualization from byte code to human + * readable form (JS compatible syntax). It uses Code2JS base class as + * a parent. + * + * @author flatline + */ +const Num = require('./../../../../vm/Num'); +const Helper = require('./../../../../../../common/src/Helper'); +const BaseCode2JS = require('./../../../../vm/Code2JS'); + +class Code2JS extends BaseCode2JS { + constructor(manager) { + super(); + + this._manager = manager; + /** + * {Object} These operator handlers should return string representation + * of numeric based byte vm. + */ + this.operators[0b101011] = this._onLookAt.bind(this); + this.operators[0b101100] = this._onStep.bind(this); + this.operators[0b101101] = this._onDir.bind(this); + this.operators[0b101110] = this._onMyX.bind(this); + this.operators[0b101111] = this._onMyY.bind(this); + this.operators[0b110000] = this._onEat.bind(this); + this.operators[0b110001] = this._onPut.bind(this); + this.operators[0b110010] = this._onEnergy.bind(this); + this.operators[0b110011] = this._onPick.bind(this); + this.operators[0b110100] = this._onRand.bind(this); + this.operators[0b110101] = this._onSay.bind(this); + this.operators[0b110110] = this._onListen.bind(this); + this.operators[0b110111] = this._onCheck.bind(this); + this.operators[0b111000] = this._onMyEnergy.bind(this); + this.operators[0b111001] = this._onPoison.bind(this); + // + // API of the Manager for accessing outside. (e.g. from Console) + // + 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() { + super.destroy(); + this._manager = null; + } + + _onLookAt(num) {return `v${Num.getVar0(num)}=lookAt(v${Num.getVar1(num)},v${Num.getVar2(num)})`} + _onStep() {return `step()`} + _onDir(num) {return `dir(v${Num.getVar0(num)})`} + _onMyX(num) {return `v${Num.getVar0(num)}=myX()`} + _onMyY(num) {return `v${Num.getVar0(num)}=myY()`} + _onEat(num) {return `eat(v${Num.getVar0(num)})`} + _onPut(num) {return `put(v${Num.getVar0(num)})`} + _onEnergy(num) {return `energy(v${Num.getVar0(num)})`} + _onPick(num) {return `pick(v${Num.getVar0(num)})`} + _onRand(num) {return `rand(v${Num.getVar0(num)})`} + _onSay(num) {return `say(v${Num.getVar0(num)})`} + _onListen(num) {return `v${Num.getVar0(num)}=listen()`} + _onCheck(num) {return `v${Num.getVar0(num)}=check()`} + _onMyEnergy(num) {return `v${Num.getVar0(num)}=myEnergy()`} + _onPoison(num) {return `poison()`} +} + +module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/dos/Code2String.js b/client/src/manager/plugins/organisms/dos/Code2String.js deleted file mode 100644 index 51c7642..0000000 --- a/client/src/manager/plugins/organisms/dos/Code2String.js +++ /dev/null @@ -1,255 +0,0 @@ -/** - * This class is used only for code visualization in readable human like form. - * It converts numeric based byte code into JS string. This class must be - * synchronized with 'Operators' one. - * - * @author flatline - */ -const Num = require('./../../../../vm/Num'); -const OConfig = require('./../Config'); -const Helper = require('./../../../../../../common/src/Helper'); -/** - * {Function} Just a shortcuts - */ -const FOUR_BITS = 4; -const CONDITION_BITS = 2; - -class Code2String { - constructor(manager) { - this._manager = manager; - /** - * {Object} These operator handlers should return string representation - * of numeric based byte vm. - */ - this._OPERATORS_CB = [ - this._onVar.bind(this), - this._onConst.bind(this), - this._onCondition.bind(this), - this._onLoop.bind(this), - this._onOperator.bind(this), - this._onLookAt.bind(this), - this._onEatLeft.bind(this), - this._onEatRight.bind(this), - this._onEatUp.bind(this), - this._onEatDown.bind(this), - this._onStepLeft.bind(this), - this._onStepRight.bind(this), - this._onStepUp.bind(this), - this._onStepDown.bind(this), - this._onFromMem.bind(this), - this._onToMem.bind(this), - this._onMyX.bind(this), - this._onMyY.bind(this), - this._onCheckLeft.bind(this), - this._onCheckRight.bind(this), - this._onCheckUp.bind(this), - this._onCheckDown.bind(this) - ]; - this._OPERATORS_CB_LEN = this._OPERATORS_CB.length; - /** - * {Array} Available conditions for if operator. Amount should be - * the same like (1 << Num.BITS_PER_VAR) - */ - this._CONDITIONS = ['<', '>', '==', '!=']; - /** - * {Array} Available operators for math calculations - */ - this._OPERATORS = [ - '+', '-', '*', '/', '%', '&', '|', '^', '>>', '<<', '>>>', '<', '>', '==', '!=', '<=' - ]; - /** - * {Array} Contains closing bracket offset for "if", "loop",... operators - */ - this._offsets = [0]; - - // TODO: fix this - Num.init(12);//this._OPERATORS_CB_LEN); - - this._BITS_AFTER_ONE_VAR = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR; - this._BITS_AFTER_TWO_VARS = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR * 2; - this._BITS_AFTER_THREE_VARS = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR * 3; - // - // API of the Manager for accessing outside. (e.g. from Console) - // - 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() { - this._OPERATORS_CB = null; - this._CONDITIONS = null; - this._OPERATORS = null; - this._offsets = null; - delete this._manager.api.formatCode; - this._manager = null; - } - - format(code, separator = '\n') { - const len = code.length; - const operators = this._OPERATORS_CB; - const offs = this._offsets; - let lines = new Array(len); - // - // 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 - // - 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 = 1; i < offs.length; i++) { - lines[length] += '}'; - } - - return js_beautify(lines.join(separator), {indent_size: 4}); - } - - /** - * Parses variable operator. Format: let = const|number. Num bits format: - * Num.BITS_PER_OPERATOR bits - operator id - * Num.BITS_PER_VAR bits - destination var index - * Num.BITS_PER_VAR bits - assign type (const (half of bits) or variable (half of bits)) - * Num.BITS_PER_VAR bits - variable index or all bits till the end for constant - * - * @param {Num} num Packed into number vm line - * @return {String} Parsed vm line string - */ - _onVar(num) { - return `v${Num.getVar0(num)}=${'v' + Num.getVar1(num)}`; - } - - _onConst(num) { - return `v${Num.getVar0(num)}=${Num.getBits(num, this._BITS_AFTER_ONE_VAR, OConfig.codeConstBits)}`; - } - - _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, blockOffs)); - return `if(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){`; - } - - _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, blockOffs)); - return `while(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){`; - } - - _onOperator(num) { - return `v${Num.getVar0(num)}=v${Num.getVar1(num)}${this._OPERATORS[Num.getBits(num, this._BITS_AFTER_THREE_VARS, FOUR_BITS)]}v${Num.getVar2(num)}`; - } - - _onLookAt(num) { - return `v${Num.getVar0(num)}=lookAt(v${Num.getVar1(num)},v${Num.getVar2(num)})`; - } - - _onEatLeft(num) { - return `v${Num.getVar0(num)}=eatLeft(v${Num.getVar1(num)})`; - } - - _onEatRight(num) { - return `v${Num.getVar0(num)}=eatRight(v${Num.getVar1(num)})`; - } - - _onEatUp(num) { - return `v${Num.getVar0(num)}=eatUp(v${Num.getVar1(num)})`; - } - - _onEatDown(num) { - return `v${Num.getVar0(num)}=eatDown(v${Num.getVar1(num)})`; - } - - _onStepLeft(num) { - return `v${Num.getVar0(num)}=stepLeft()`; - } - - _onStepRight(num) { - return `v${Num.getVar0(num)}=stepRight()`; - } - - _onStepUp(num) { - return `v${Num.getVar0(num)}=stepUp()`; - } - - _onStepDown(num) { - return `v${Num.getVar0(num)}=stepDown()`; - } - - _onFromMem(num) { - if (Num.getBits(num, this._BITS_AFTER_TWO_VARS, 1)) { - return `v${Num.getVar0(num)}=fromMem(v${Num.getVar1(num)})`; - } - - const offs = Num.getBits(num, this._BITS_AFTER_TWO_VARS + 1, OConfig.orgMemBits); - return `v${Num.getVar0(num)}=fromMem(${offs})`; - } - - _onToMem(num) { - if (Num.getBits(num, this._BITS_AFTER_TWO_VARS, 1)) { - return `toMem(v${Num.getVar0(num)},v${Num.getVar1(num)})`; - } - return `toMem(v${Num.getVar0(num)},${Num.getBits(num, this._BITS_AFTER_TWO_VARS, OConfig.orgMemBits)})`; - } - - _onMyX(num) { - return `v${Num.getVar0(num)}=myX()`; - } - - _onMyY(num) { - return `v${Num.getVar0(num)}=myY()`; - } - - _onCheckLeft(num) { - return `v${Num.getVar0(num)}=checkLeft()`; - } - - _onCheckRight(num) { - return `v${Num.getVar0(num)}=checkRight()`; - } - - _onCheckUp(num) { - return `v${Num.getVar0(num)}=checkUp()`; - } - - _onCheckDown(num) { - return `v${Num.getVar0(num)}=checkDown()`; - } - - /** - * Returns offset for closing bracket of blocked operators like - * "if", "for" and so on. These operators shouldn't overlap each - * other. for example: - * - * for (...) { // 0 - * if (...) { // 1 - * ... // 2 - * } // 3 - * } // 4 - * - * Closing bracket in line 3 shouldn't be after bracket in line 4. - * 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} offs Local offset of closing bracket we want to set - * @returns {Number} - */ - _getOffs(line, offs) { - const offsets = this._offsets || [0]; - return line + offs > offsets[offsets.length - 1] ? offsets[offsets.length - 1] : line + offs; - } -} - -module.exports = Code2String; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index aa40d6e..d6bcdea 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -34,7 +34,7 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { - const bitsPerOp = OConfig.codeBitsPerOperator; + const bitsPerOp = OConfig.CODE_BITS_PER_OPERATOR; this.OPERATOR_AMOUNT = 26; // // IMPORTANT: don't use super here, because it breaks Operators diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 16da5a2..2a66406 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1213,7 +1213,7 @@ describe("client/src/organism/OperatorsDos", () => { ocfg = new ConfigHelper(OConfig); ocfg.set('codeYieldPeriod', 2); ocfg.set('codeBitsPerBlock', 8); - ocfg.set('codeBitsPerOperator', 8); + ocfg.set('CODE_BITS_PER_OPERATOR', 8); ocfg.set('codeBitsPerVar', 2); ocfg.set('codeConstBits', 16); ocfg.set('orgMemBits', 8); diff --git a/client/src/manager/plugins/organisms/garmin/Code2String.js b/client/src/manager/plugins/organisms/garmin/Code2String.js index 034b478..5f2b49f 100644 --- a/client/src/manager/plugins/organisms/garmin/Code2String.js +++ b/client/src/manager/plugins/organisms/garmin/Code2String.js @@ -16,7 +16,7 @@ const VAR2 = (n) => Num.getVar(n, 2); const BITS_AFTER_THREE_VARS = Num.BITS_PER_OPERATOR + Num.BITS_PER_VAR * 3; const HALF_OF_VAR = Num.MAX_VAR / 2; -class Code2String { +class Code2JS { constructor(manager) { this._manager = manager; /** @@ -130,4 +130,4 @@ class Code2String { } } -module.exports = Code2String; \ No newline at end of file +module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 506ecbc..0975e4d 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -35,7 +35,7 @@ ClientConfig.init({ */ plugIncluded: [ 'organisms/dos/Organisms', - 'organisms/dos/Code2String', + 'organisms/dos/Code2JS', 'Config', 'client/Client', 'energy/Energy', diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js new file mode 100644 index 0000000..a4529a7 --- /dev/null +++ b/client/src/vm/Code2JS.js @@ -0,0 +1,128 @@ +/** + * This class is used only for code translation from byte code to JavaScript + * in readable human like form. It translates only base operators. Generally + * all you need to do is create an instance and call format() method with a + * byte code as a parameter. + * + * @author flatline + */ +const Num = require('./../vm/Num'); +const OConfig = require('./../manager/plugins/organisms/Config'); +const Operators = require('./Operators'); + +class Code2JS { + constructor() { + /** + * @constant + * {Array} Available condition operations for if, while and math operators. Amount + * of operations should be 16 (4 bits). + */ + this._CONDITIONS = ['+','-','*','/','%','&','|','^','>>','<<','>>>','<','>','==','!=','<=']; + /** + * {Object} These operator handlers should return string representation + * of numeric based byte vm. + */ + this._operators = { + 0b100000: this._onVar.bind(this), + 0b100001: this._onConst.bind(this), + 0b100010: this._onIf.bind(this), + 0b100011: this._onLoop.bind(this), + 0b100100: this._onOperator.bind(this), + 0b100101: this._onFunc.bind(this), + 0b100110: this._onFuncCall.bind(this), + 0b100111: this._onReturn.bind(this), + 0b101000: this._onBracket.bind(this), + 0b101001: this._onToMem.bind(this), + 0b101010: this._onFromMem.bind(this) + }; + } + + get operators() { + return this._operators; + } + + format(code, separator = '\n') { + const len = code.length; + const operators = this._operators; + let jsCode = new Array(len); + const offs = new Array(len); + const vars = new Array(Math.pow(2, OConfig.codeBitsPerVar)); + const ops = new Operators(offs, vars); + + ops.updateIndexes(code); + for (let line = 0; line < len; line++) { + jsCode[line] = operators[Num.getOperator(code[line])](code[line], line, ops); + } + ops.destroy(); + + return js_beautify(jsCode.join(separator), {indent_size: 4}); + } + + destroy() { + this._operators = null; + this._CONDITIONS = null; + } + + /** + * Parses var operator. Format: var1 = var0. + * @param {Num} num Packed into number vm line + * @return {String} Parsed vm line string + */ + _onVar(num) { + return `v${Num.getVar0(num)}=v${Num.getVar1(num)}`; + } + + _onConst(num) { + return `v${Num.getVar0(num)}=${Num.getBits(num, Num.BITS_OF_VAR1, OConfig.codeConstBits)}`; + } + + _onIf(num, line, ops) { + const cond = Num.getBits(num, Num.BITS_OF_VAR2, ops.CONDITION_BITS); + const bracket = ops.offs[line] === line ? '}' : ''; + return `if(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){${bracket}`; + } + + _onLoop(num, line, ops) { + const cond = Num.getBits(num, Num.BITS_OF_VAR2, ops.CONDITION_BITS); + const bracket = ops.offs[line] === line ? '}' : ''; + return `while(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){${bracket}`; + } + + _onOperator(num, line, ops) { + return `v${Num.getVar0(num)}=v${Num.getVar1(num)}${this._CONDITIONS[Num.getBits(num, Num.BITS_OF_VAR3, ops.CONDITION_BITS)]}v${Num.getVar2(num)}`; + } + + _onFunc(num, line, ops) { + const bracket = ops.offs[line] === line ? '}' : ''; + return `func f${ops.funcs.indexOf(line + 1)}{${bracket}`; + } + + _onFuncCall(num, line, ops) { + let fn; + + if (Num.getBits(num, Num.BITS_OF_VAR0, 1) === 1) { + fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, ops.FUNC_NAME_BITS)}`; + } else { + fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar)}`; + } + return `call ${fn}()`; + } + + _onReturn() { + return 'return'; + } + + _onBracket(num, line, ops) { + return typeof ops.offs[line] === 'undefined' ? '// }' : '}'; + } + + _onToMem(num) { + return `toMem(v${Num.getVar0(num)},v${Num.getVar1(num)}`; + } + + _onFromMem(num) { + return `v${Num.getVar0(num)}=fromMem(v${Num.getVar1(num)}`; + } +} + +module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/vm/Num.js b/client/src/vm/Num.js index 3c167b7..44d0170 100644 --- a/client/src/vm/Num.js +++ b/client/src/vm/Num.js @@ -17,7 +17,7 @@ class Num { this.MAX_BITS = 32; this.OPERATOR_AMOUNT = operatorAmount; this.BITS_PER_VAR = OConfig.codeBitsPerVar; - this.BITS_PER_OPERATOR = OConfig.codeBitsPerOperator; + this.BITS_PER_OPERATOR = OConfig.CODE_BITS_PER_OPERATOR; this.NO_OPERATOR_MASK = 0xffffffff >>> this.BITS_PER_OPERATOR; this.OPERATOR_MASK_ON = 0x80000000; this.OPERATOR_MASK_OFF = 0x7fffffff; @@ -44,7 +44,7 @@ class Num { } static getOperator(num) { - return (num & this.OPERATOR_MASK_OFF) >>> this.VAR_BITS_OFFS; + return num >>> this.VAR_BITS_OFFS; } static setOperator(num, op) { diff --git a/client/src/vm/NumSpec.js b/client/src/vm/NumSpec.js index 5934658..d12401a 100644 --- a/client/src/vm/NumSpec.js +++ b/client/src/vm/NumSpec.js @@ -2,18 +2,17 @@ let Num = require('./Num'); let OConfig = require('./../manager/plugins/organisms/Config'); describe("client/src/organism/Num", () => { - const bpo = OConfig.codeBitsPerOperator; const bpv = OConfig.codeBitsPerVar; - beforeEach(() => {OConfig.codeBitsPerOperator = 8; OConfig.codeBitsPerVar = 2}); - afterEach( () => {OConfig.codeBitsPerOperator = bpo; OConfig.codeBitsPerVar = bpv}); + beforeEach(() => {OConfig.codeBitsPerVar = 2}); + afterEach( () => {OConfig.codeBitsPerVar = bpv}); describe('Checks initialization', () => { it ('Checks init() method', () => { Num.init(3); expect(Num.OPERATOR_AMOUNT).toBe(3); expect(Num.BITS_PER_VAR).toBe(OConfig.codeBitsPerVar); - expect(Num.BITS_PER_OPERATOR).toBe(OConfig.codeBitsPerOperator); + expect(Num.BITS_PER_OPERATOR).toBe(OConfig.CODE_BITS_PER_OPERATOR); }); }); diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index b51e2da..7aa35fe 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -17,7 +17,7 @@ class Operators { * @param {Number} operators Amount of operators */ static compile(operators = OPERATOR_AMOUNT) { - const bitsPerOp = OConfig.codeBitsPerOperator; + const bitsPerOp = OConfig.CODE_BITS_PER_OPERATOR; const MAX_BITS = 32; /** * {Object} Container for storing of dynamic operator handlers @@ -26,7 +26,6 @@ class Operators { /** * {Number} Bit related constants */ - this.FOUR_BITS = 4; this.CONDITION_BITS = 4; this.FUNC_NAME_BITS = 8; /** @@ -65,7 +64,7 @@ class Operators { MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar), // const MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2 + this.CONDITION_BITS), // if MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2 + this.CONDITION_BITS), // loop - MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3 + this.FOUR_BITS), // math + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3 + this.CONDITION_BITS), // math MAX_BITS - (bitsPerOp), // func MAX_BITS - (bitsPerOp), // func call MAX_BITS - (bitsPerOp), // return @@ -228,7 +227,7 @@ class Operators { const h = Helper.toHexNum; const b = Helper.toBinStr; const vars = Math.pow(2, bpv); - const opsLen = Math.pow(2, this.FOUR_BITS); + const opsLen = Math.pow(2, this.CONDITION_BITS); for (let op = 0; op < opsLen; op++) { for (let v0 = 0; v0 < vars; v0++) { @@ -238,7 +237,7 @@ class Operators { ${this._OPERATORS[op](v0, v1, v2)} return ++line; }`); - ops[h(`${'100100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}${b(op, this.FOUR_BITS)}`)] = this.global.fn; + ops[h(`${'100100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}${b(op, this.CONDITION_BITS)}`)] = this.global.fn; } } } @@ -344,13 +343,12 @@ class Operators { const ops = this._compiledOperators; const h = Helper.toHexNum; const vars = Math.pow(2, OConfig.codeBitsPerVar); - const opMask = Num.OPERATOR_MASK_OFF; eval(`Operators.global.fn = function bracket(line, num, org, lines) { const startLine = this.offs[line]; - const operator = typeof startLine === 'undefined' ? -1 : (lines[startLine] & ${opMask}) >>> Num.VAR_BITS_OFFS; - if (operator === 0x3) {return this.offs[line]} // loop - if (operator === 0x5) { // func + const operator = typeof startLine === 'undefined' ? -1 : lines[startLine] >>> Num.VAR_BITS_OFFS; + if (operator === 0b100011) {return this.offs[line]} // loop + if (operator === 0b100101) { // func const stack = this.stack; if (stack[stack.length - 2] === startLine) { const stackVars = stack.pop(); @@ -451,7 +449,6 @@ class Operators { updateIndexes(code) { const len = code.length; const varOffs = Num.VAR_BITS_OFFS; - const opMask = Num.OPERATOR_MASK_OFF; const offs = this.offs; const funcs = this.funcs = new Array(this._MAX_FUNC_AMOUNT); const blocks = []; @@ -459,19 +456,19 @@ class Operators { this.stack = []; for (let i = 0; i < len; i++) { - const operator = (code[i] & opMask) >>> varOffs; - if (operator === 0x2 || operator === 0x3) { // if, while + const operator = code[i] >>> varOffs; + if (operator === 0b100010 || operator === 0b100011) { // if, while offs[i] = i; blocks.push(i); continue; } - if (operator === 0x5) { // func + if (operator === 0b100101) { // func offs[i] = i; funcs[func++] = i + 1; blocks.push(i); continue; } - if (operator === 0x8) { // bracket + if (operator === 0b101000) { // bracket if (blocks.length > 0) { offs[i] = blocks.pop(); offs[offs[i]] = i + 1; From f70853fd6db6a4f14030a7cb0c6443793f24a93f Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 22 May 2018 19:26:12 +0300 Subject: [PATCH 41/88] added Code2JS classes operator bits config has moved to the constant section of configuration --- .../manager/plugins/organisms/dos/Code2JS.js | 2 +- .../plugins/organisms/dos/Operators.js | 4 +- .../plugins/organisms/dos/OperatorsSpec.js | 1036 ++--------------- client/src/vm/Code2JS.js | 6 +- client/src/vm/OperatorsSpec.js | 2 +- 5 files changed, 101 insertions(+), 949 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Code2JS.js b/client/src/manager/plugins/organisms/dos/Code2JS.js index 35fdeea..80b4921 100644 --- a/client/src/manager/plugins/organisms/dos/Code2JS.js +++ b/client/src/manager/plugins/organisms/dos/Code2JS.js @@ -53,7 +53,7 @@ class Code2JS extends BaseCode2JS { _onPut(num) {return `put(v${Num.getVar0(num)})`} _onEnergy(num) {return `energy(v${Num.getVar0(num)})`} _onPick(num) {return `pick(v${Num.getVar0(num)})`} - _onRand(num) {return `rand(v${Num.getVar0(num)})`} + _onRand(num) {return `v${Num.getVar0(num)}=rand(v${Num.getVar1(num)})`} _onSay(num) {return `say(v${Num.getVar0(num)})`} _onListen(num) {return `v${Num.getVar0(num)}=listen()`} _onCheck(num) {return `v${Num.getVar0(num)}=check()`} diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index d6bcdea..8bfc55f 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -82,8 +82,8 @@ class OperatorsDos extends Operators { * depends on configuration. '...' means, that all other bits are * ignored. Example: * - * bits : 6 xx xx xx 4 - * number: 101011 00 01 00 01... + * bits : 6 xx xx xx + * number: 101011 00 01 00... * string: v0 = lookAt(v1, v0) */ static _compileLookAt() { diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 2a66406..318be9a 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1,286 +1,41 @@ -const _fill = require('lodash/fill'); - -describe("client/src/organism/OperatorsDos", () => { - const OConfig = require('./../../organisms/Config'); - const THelper = require('./../../../../../../common/tests/Helper'); - const cbpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 2; - const OperatorsDos = require('./Operators'); - const EVENTS = require('./../../../../share/Events').EVENTS; - const Config = require('./../../../../share/Config').Config; - const OrganismDos = require('./../../organisms/dos/Organism'); - const ConfigHelper = require('./../../../../../../common/tests/Config'); - - afterAll(() => OConfig.codeBitsPerVar = cbpv); - - describe('Checks creation, destroy and public API', () => { - it('Checking instance creation', () => { - let offs = []; - let vars = []; - let obs = {}; - let ops = new OperatorsDos(offs, vars, obs); - expect(ops.offs).toBe(offs); - expect(ops.vars).toBe(vars); - expect(ops.obs).toBe(obs); - ops.destroy(); - }); - it('Checking destroy', () => { - let offs = []; - let vars = []; - let obs = {}; - let ops = new OperatorsDos(offs, vars, obs); - ops.destroy(); - expect(ops.offsets).not.toBe(offs); - expect(ops.vars).not.toBe(vars); - expect(ops.obs).not.toBe(obs); - }); - it('Checking operators getter', () => { - let offs = []; - let vars = []; - let obs = {}; - let ops = new OperatorsDos(offs, vars, obs); - expect(Array.isArray(ops.operators)).toBe(true); - expect(ops.operators.length > 0).toBe(true); - ops.destroy(); - }); +const _fill = require('lodash/fill'); +const Operators = require('./Operators'); +const OConfig = require('./../../../plugins/organisms/Config'); +const Helper = require('./../../../../../../common/src/Helper'); + +describe("client/src/manager/plugins/organisms/OperatorsDos", () => { + const h = Helper.toHexNum; + const MAX_NUM = Number.MAX_VALUE; + let cbpv; + let ccb; + let ops; + let offs; + let vars; + + beforeAll (() => { + cbpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 2; + ccb = OConfig.codeConstBits; + OConfig.codeConstBits = 3; + Operators.compile(); }); - - describe('onVar() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it("Checking variables working", () => { - expect(ops.onVar(0x00dfffff, 0)).toEqual(1); // 0xd === 0b1101, var3 = var1 - expect(ops.vars).toEqual([0, 1, 2, 1]); - expect(ops.onVar(0x000fffff, 0)).toEqual(1); // 0x0 === 0b0000, var0 = var0 - expect(ops.vars).toEqual([0, 1, 2, 1]); - expect(ops.onVar(0x006fffff, 0)).toEqual(1); // 0x6 === 0b0110, var1 = var2 - expect(ops.vars).toEqual([0, 2, 2, 1]); - expect(ops.onVar(0x00ffffff, 0)).toEqual(1); // 0xf === 0b1111, var3 = var3 - expect(ops.vars).toEqual([0, 2, 2, 1]); - }); - - it("Checking onVar() method with 3 bits per var config", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([], [0, 1, 2, 3, 4, 5, 6, 7], org); - - expect(ops1.onVar(0x00ffffff, 0)).toEqual(1); // 0xff === 0b[111111]11, var7 = var7 - expect(ops1.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); - expect(ops1.onVar(0x005dffff, 0)).toEqual(1); // 0x5d === 0b[010111]01, var2 = var7 - expect(ops1.vars).toEqual([0, 1, 7, 3, 4, 5, 6, 7]); - expect(ops1.onVar(0x005fffff, 0)).toEqual(1); // 0x5f === 0b[010111]11, var2 = var7 - expect(ops1.vars).toEqual([0, 1, 7, 3, 4, 5, 6, 7]); - expect(ops1.onVar(0x0000ffff, 0)).toEqual(1); // 0x00 === 0b[000000]00, var0 = var0 - expect(ops1.vars).toEqual([0, 1, 7, 3, 4, 5, 6, 7]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - - it('Checking line increase', () => { - expect(ops.onVar(0x000fffff, 0)).toEqual(1); // 0x0 === 0b0000, var0 = var0 - expect(ops.onVar(0x000fffff, 1)).toEqual(2); // 0x0 === 0b0000, var0 = var0 - expect(ops.onVar(0x000fffff, 100)).toEqual(101); // 0x0 === 0b0000, var0 = var0 - }); - }); - - describe('onConst() method', () => { - let org; - let ops; - let codeConstBits = OConfig.codeConstBits; - OConfig.codeConstBits = 16; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - afterAll (() => OConfig.codeConstBits = codeConstBits); - - it("Checking different constant values", () => { - expect(ops.onConst(0x01dfffff, 0)).toEqual(1); // 0xdffff === 0b[11][0111111111111111]11, var3 = 0x7fff - expect(ops.vars).toEqual([0, 1, 2, 0x7fff]); - expect(ops.onConst(0x010fffff, 0)).toEqual(1); // 0x0ffff === 0b[00][0011111111111111]11, var0 = 0x3fff - expect(ops.vars).toEqual([0x3fff, 1, 2, 0x7fff]); - expect(ops.onConst(0x01000000, 0)).toEqual(1); // 0x00000 === 0b[00][0000000000000000]00, var0 = 0x0000 - expect(ops.vars).toEqual([0, 1, 2, 0x7fff]); - }); - - it("Checking onConst() method with 3 bits per var config", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([], [0, 1, 2, 3, 4, 5, 6, 7], org); - - expect(ops1.onConst(0x01ffffff, 0)).toEqual(1); // 0xfffff === 0b[111][1111111111111111]1, var7 = 0xffff - expect(ops1.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 0xffff]); - expect(ops1.onConst(0x015dffff, 0)).toEqual(1); // 0x5dfff === 0b[010][1110111111111111]1, var2 = 0xefff - expect(ops1.vars).toEqual([0, 1, 0xefff, 3, 4, 5, 6, 0xffff]); - expect(ops1.onConst(0x0100ffff, 0)).toEqual(1); // 0x00fff === 0b[000][0000011111111111]1, var0 = 0x07ff - expect(ops1.vars).toEqual([0x07ff, 1, 0xefff, 3, 4, 5, 6, 0xffff]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - - it('Checking line increase', () => { - expect(ops.onConst(0x01ffffff, 0)).toEqual(1); // 0xfffff === 0b[111][1111111111111111]1, var7 = 0xffff - expect(ops.onConst(0x015dffff, 1)).toEqual(2); // 0x5dfff === 0b[010][1110111111111111]1, var2 = 0xefff - expect(ops.onConst(0x0100ffff, 700)).toEqual(701); // 0x00fff === 0b[000][0000011111111111]1, var0 = 0x07ff - }); - }); - - describe('onCondition() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it("Checking conditions", () => { - expect(ops.onCondition(0x02ffffff, 0)).toEqual(1); //if(v3!==v3); - ops.offsets = [1]; - expect(ops.onCondition(0x021fffff, 0)).toEqual(1); //if(v0!==v1); - ops.offsets = [1]; - expect(ops.onCondition(0x021abfff, 0)).toEqual(1); //if(v0===v1); - ops.offsets = [1]; - expect(ops.onCondition(0x0213ffff, 0)).toEqual(1); //if(v0 < v1); - }); - - it('Checking closing bracket offset', () => { - ops.offsets = [2]; - expect(ops.onCondition(0x02ffffff, 0)).toEqual(2); //if(v3!==v3); - ops.offsets = [1]; - expect(ops.onCondition(0x02ffffff, 0)).toEqual(1); //if(v3!==v3); - ops.offsets = [1]; - expect(ops.onCondition(0x0213ffff, 0)).toEqual(1); //if(v0 < v1); - }); - - it("Checking onCondition() method with 3 bits per var config", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([], [0, 1, 2, 3, 4, 5, 6, 7], org); - - ops.offsets = [2]; - expect(ops.onCondition(0x02ffffff, 0)).toEqual(2); //if(v3!==v3); - ops.offsets = [2]; - expect(ops.onCondition(0x021fffff, 0)).toEqual(1); //if(v0!==v7); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); + afterAll (() => { + OConfig.codeBitsPerVar = cbpv; + OConfig.codeConstBits = ccb; }); - - describe('onLoop() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it("Checking conditions", () => { - expect(ops.onCondition(0x03ffffff, 0)).toEqual(1); //while(v3!==v3); - ops.offsets = [1]; - expect(ops.onCondition(0x031fffff, 0)).toEqual(1); //while(v0!==v1); - ops.offsets = [1]; - expect(ops.onCondition(0x031abfff, 0)).toEqual(1); //while(v0===v1); - ops.offsets = [1]; - expect(ops.onCondition(0x0313ffff, 0)).toEqual(1); //while(v0 < v1); - }); - - it('Checking closing bracket offset', () => { - ops.offsets = [2]; - expect(ops.onCondition(0x03ffffff, 0)).toEqual(2); //while(v3!==v3); - ops.offsets = [1]; - expect(ops.onCondition(0x03ffffff, 0)).toEqual(1); //while(v3!==v3); - ops.offsets = [1]; - expect(ops.onCondition(0x0313ffff, 0)).toEqual(1); //while(v0 < v1); - }); - - it("Checking onLoop() method with 3 bits per var config", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([], [0, 1, 2, 3, 4, 5, 6, 7], org); - - ops.offsets = [2]; - expect(ops.onCondition(0x03ffffff, 0)).toEqual(2); //while(v3!==v3); - ops.offsets = [2]; - expect(ops.onCondition(0x031fffff, 0)).toEqual(1); //while(v0!==v7); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); + beforeEach(() => { + vars = [0,1,2,3]; + offs = new Array(10); + ops = new Operators(offs, vars); }); - - describe('onOperator() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it("Checking onOperator() method", () => { - expect(ops.onOperator(0x045a3fff, 0)).toEqual(1); //v1=v1>>v2; - expect(ops.vars).toEqual([0, 0, 2, 3]); - expect(ops.onOperator(0x046c7fff, 1)).toEqual(2); //v1=v2-v3; - expect(ops.vars).toEqual([0, -1, 2, 3]); - expect(ops.onOperator(0x046fffff, 3)).toEqual(4); //v1=v2<=v3; - expect(ops.vars).toEqual([0, 1, 2, 3]); - expect(ops.onOperator(0x04ffffff, 7)).toEqual(8); //v3=v3<=v3; - expect(ops.vars).toEqual([0, 1, 2, 1]); - expect(ops.onOperator(0x046d3fff, 0)).toEqual(1); //v1=v2%v3; - expect(ops.vars).toEqual([0, 0, 2, 1]); - - expect(ops.onOperator(0x046c3fff, 0)).toEqual(1); //v1=v2+v3; - expect(ops.vars).toEqual([0, 3, 2, 1]); - expect(ops.onOperator(0x046c7fff, 0)).toEqual(1); //v1=v2-v3; - expect(ops.vars).toEqual([0, 1, 2, 1]); - expect(ops.onOperator(0x046cbfff, 0)).toEqual(1); //v1=v2*v3; - expect(ops.vars).toEqual([0, 2, 2, 1]); - ops.vars = [0, 1, 2, 4]; - expect(ops.onOperator(0x046cffff, 0)).toEqual(1); //v1=v2/v3; - expect(ops.vars).toEqual([0, .5, 2, 4]); - ops.vars = [0, 1, 2, 3]; - expect(ops.onOperator(0x046d3fff, 0)).toEqual(1); //v1=v2%v3; - expect(ops.vars).toEqual([0, 2, 2, 3]); - }); - - it('Checking onOperator() with 4 bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - expect(ops1.onOperator(0x04ffffff, 0)).toEqual(1); //v15=v15<=v15 - expect(ops1.vars).toEqual([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,1]); - expect(ops1.onOperator(0x046ff0ff, 0)).toEqual(1); //v6=v15+v15 - expect(ops1.vars).toEqual([0,1,2,3,4,5,2,7,8,9,10,11,12,13,14,1]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - - it("Checking overflows", () => { - const max = Number.MAX_VALUE; - - ops.vars = [0, 1, max, max]; - expect(ops.onOperator(0x046c3fff, 0)).toEqual(1); //v1=v2+v3; - expect(ops.vars).toEqual([0, max, max, max]); - ops.vars = [0, 1, -max, max]; - expect(ops.onOperator(0x046c7fff, 0)).toEqual(1); //v1=v2-v3; - expect(ops.vars).toEqual([0, -max, -max, max]); - ops.vars = [0, 1, max, max]; - expect(ops.onOperator(0x046cbfff, 0)).toEqual(1); //v1=v2*v3; - expect(ops.vars).toEqual([0, max, max, max]); - ops.vars = [0, 1, max, 0]; - expect(ops.onOperator(0x046cffff, 0)).toEqual(1); //v1=v2/v3; - expect(ops.vars).toEqual([0, max, max, 0]); - ops.vars = [0, 1, 2, 0]; - expect(ops.onOperator(0x046d3fff, 0)).toEqual(1); //v1=v2%v3; - expect(ops.vars).toEqual([0, 0, 2, 0]); - }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; }); - describe('onLookAt() method', () => { + xdescribe('onLookAt() method', () => { let org; let ops; const w = Config.worldWidth; @@ -343,370 +98,12 @@ describe("client/src/organism/OperatorsDos", () => { ret.ret = 13; }); ops.vars = [0, 1, .1, 3.6]; - expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); - expect(ops.vars).toEqual([0,13,.1,3.6]); - }); - }); - - describe('onEatLeft() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking eating nothing", () => { - ops.vars = [1, 0, 1, 2]; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([0, 0, 1, 2]); - }); - it("Checking eating nothing 2", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 0; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([0,1,2,3]); - }); - - it("Checking eating energy", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([5,1,2,3]); - }); - - it('Checking eating with 3bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); - - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(4); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops1.onEatLeft(0x0633ffff, 0, org)).toEqual(1); // v1=eatLeft(v4); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }) - }); - - describe('onEatRight() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking eating nothing", () => { - ops.vars = [1, 0, 1, 2]; - expect(ops.onEatRight(0x071fffff, 0, org)).toEqual(1); // v0=eatRight(v1); - expect(ops.vars).toEqual([0, 0, 1, 2]); - }); - it("Checking eating nothing 2", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(3); - expect(y).toBe(3); - ret.ret = 0; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatRight(0x071fffff, 0, org)).toEqual(1); // v0=eatRight(v1); - expect(ops.vars).toEqual([0,1,2,3]); - }); - - it("Checking eating energy", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(3); - expect(y).toBe(3); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatRight(0x071fffff, 0, org)).toEqual(1); // v0=eatRight(v1); - expect(ops.vars).toEqual([5,1,2,3]); - }); - - it('Checking eating with 3bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); - - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(4); - expect(x).toBe(3); - expect(y).toBe(3); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops1.onEatRight(0x0733ffff, 0, org)).toEqual(1); // v1=eatRight(v4); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }) - }); - - describe('onEatUp() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking eating nothing", () => { - ops.vars = [1, 0, 1, 2]; - expect(ops.onEatUp(0x081fffff, 0, org)).toEqual(1); // v0=eatUp(v1); - expect(ops.vars).toEqual([0, 0, 1, 2]); - }); - it("Checking eating nothing 2", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(2); - expect(y).toBe(2); - ret.ret = 0; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatUp(0x081fffff, 0, org)).toEqual(1); // v0=eatUp(v1); - expect(ops.vars).toEqual([0,1,2,3]); - }); - - it("Checking eating energy", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(2); - expect(y).toBe(2); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatUp(0x081fffff, 0, org)).toEqual(1); // v0=eatUp(v1); - expect(ops.vars).toEqual([5,1,2,3]); - }); - - it('Checking eating with 3bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); - - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(4); - expect(x).toBe(2); - expect(y).toBe(2); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops1.onEatUp(0x0833ffff, 0, org)).toEqual(1); // v1=eatUp(v4); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }) - }); - - describe('onEatDown() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking eating nothing", () => { - ops.vars = [1, 0, 1, 2]; - expect(ops.onEatDown(0x091fffff, 0, org)).toEqual(1); // v0=eatDown(v1); - expect(ops.vars).toEqual([0, 0, 1, 2]); - }); - it("Checking eating nothing 2", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(2); - expect(y).toBe(4); - ret.ret = 0; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatDown(0x091fffff, 0, org)).toEqual(1); // v0=eatDown(v1); - expect(ops.vars).toEqual([0,1,2,3]); - }); - - it("Checking eating energy", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(2); - expect(y).toBe(4); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatDown(0x091fffff, 0, org)).toEqual(1); // v0=eatDown(v1); - expect(ops.vars).toEqual([5,1,2,3]); - }); - - it('Checking eating with 3bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); - - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(4); - expect(x).toBe(2); - expect(y).toBe(4); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops1.onEatDown(0x0933ffff, 0, org)).toEqual(1); // v1=eatDown(v4); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }) - }); - - describe('onStepLeft() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking step left", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); - }); - expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); - expect(ops.vars).toEqual([2,1,2,3]); - expect(org.x).toBe(2); - expect(org.y).toBe(4); - }); - - it("Checking step left with no free space on the left", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); - }); - expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); - expect(ops.vars).toEqual([0,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(4); - }); - - it("Checking step left with 4 bits per var", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); - }); - expect(ops1.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v1=stepLeft(); - expect(ops1.vars).toEqual([0,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - expect(org.x).toBe(2); - expect(org.y).toBe(4); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - - describe('onStepRight() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking step right", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 4 && y2 === 4).toBe(true); - }); - expect(ops.onStepRight(0x0a1fffff, 0, org)).toEqual(1); // v0=stepRight(); - expect(ops.vars).toEqual([4,1,2,3]); - expect(org.x).toBe(4); - expect(org.y).toBe(4); - }); - - it("Checking step right with no free space on the right", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - expect(x1 === 3 && y1 === 4 && x2 === 4 && y2 === 4).toBe(true); - }); - expect(ops.onStepRight(0x0a1fffff, 0, org)).toEqual(1); // v0=stepRight(); - expect(ops.vars).toEqual([0,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(4); - }); - - it("Checking step right with 4 bits per var", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 4 && y2 === 4).toBe(true); - }); - expect(ops1.onStepRight(0x0a1fffff, 0, org)).toEqual(1); // v1=stepRight(); - expect(ops1.vars).toEqual([0,4,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - expect(org.x).toBe(4); - expect(org.y).toBe(4); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); + expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); + expect(ops.vars).toEqual([0,13,.1,3.6]); }); }); - describe('onStepUp() method', () => { + xdescribe('onEatLeft() method', () => { let org; let ops; const w = Config.worldWidth; @@ -715,55 +112,59 @@ describe("client/src/organism/OperatorsDos", () => { beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - it("Checking step up", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 3 && y2 === 3).toBe(true); + it("Checking eating nothing", () => { + ops.vars = [1, 0, 1, 2]; + expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); + expect(ops.vars).toEqual([0, 0, 1, 2]); + }); + it("Checking eating nothing 2", () => { + org.on(EVENTS.EAT, (org, x, y, ret) => { + expect(ret.ret).toBe(1); + expect(x).toBe(1); + expect(y).toBe(3); + ret.ret = 0; }); - expect(ops.onStepUp(0x0a1fffff, 0, org)).toEqual(1); // v0=stepUp(); - expect(ops.vars).toEqual([3,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(3); + org.x = 2; + org.y = 3; + expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); + expect(ops.vars).toEqual([0,1,2,3]); }); - it("Checking step up with no free space on above", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - expect(x1 === 3 && y1 === 4 && x2 === 3 && y2 === 3).toBe(true); + it("Checking eating energy", () => { + org.on(EVENTS.EAT, (org, x, y, ret) => { + expect(ret.ret).toBe(1); + expect(x).toBe(1); + expect(y).toBe(3); + ret.ret = 5; }); - expect(ops.onStepUp(0x0a1fffff, 0, org)).toEqual(1); // v0=stepUp(); - expect(ops.vars).toEqual([0,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(4); + org.x = 2; + org.y = 3; + expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); + expect(ops.vars).toEqual([5,1,2,3]); }); - it("Checking step up with 4 bits per var", () => { + it('Checking eating with 3bits per var', () => { let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); + OConfig.codeBitsPerVar = 3; + let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 3 && y2 === 3).toBe(true); + org.on(EVENTS.EAT, (org, x, y, ret) => { + expect(ret.ret).toBe(4); + expect(x).toBe(1); + expect(y).toBe(3); + ret.ret = 5; }); - expect(ops1.onStepUp(0x0a1fffff, 0, org)).toEqual(1); // v1=stepUp(); - expect(ops1.vars).toEqual([0,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - expect(org.x).toBe(3); - expect(org.y).toBe(3); + org.x = 2; + org.y = 3; + expect(ops1.onEatLeft(0x0633ffff, 0, org)).toEqual(1); // v1=eatLeft(v4); + expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); OConfig.codeBitsPerVar = bpv; ops1.destroy(); - }); + }) }); - describe('onStepDown() method', () => { + xdescribe('onStepLeft() method', () => { let org; let ops; const w = Config.worldWidth; @@ -772,33 +173,33 @@ describe("client/src/organism/OperatorsDos", () => { beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - it("Checking step down", () => { + it("Checking step left", () => { org.x = 3; org.y = 4; org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { org.x = x2; org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 3 && y2 === 5).toBe(true); + expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); }); - expect(ops.onStepDown(0x0a1fffff, 0, org)).toEqual(1); // v0=stepDown(); - expect(ops.vars).toEqual([5,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(5); + expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); + expect(ops.vars).toEqual([2,1,2,3]); + expect(org.x).toBe(2); + expect(org.y).toBe(4); }); - it("Checking step down with no free space below", () => { + it("Checking step left with no free space on the left", () => { org.x = 3; org.y = 4; org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - expect(x1 === 3 && y1 === 4 && x2 === 3 && y2 === 5).toBe(true); + expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); }); - expect(ops.onStepDown(0x0a1fffff, 0, org)).toEqual(1); // v0=stepDown(); + expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); expect(ops.vars).toEqual([0,1,2,3]); expect(org.x).toBe(3); expect(org.y).toBe(4); }); - it("Checking step down with 4 bits per var", () => { + it("Checking step left with 4 bits per var", () => { let bpv = OConfig.codeBitsPerVar; OConfig.codeBitsPerVar = 4; let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); @@ -808,115 +209,19 @@ describe("client/src/organism/OperatorsDos", () => { org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { org.x = x2; org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 3 && y2 === 5).toBe(true); + expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); }); - expect(ops1.onStepDown(0x0a1fffff, 0, org)).toEqual(1); // v1=stepDown(); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - expect(org.x).toBe(3); - expect(org.y).toBe(5); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - - describe('onFromMem() method', () => { - let org; - let ops; - let mbits; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - beforeAll(() => {mbits = OConfig.orgMemBits; OConfig.orgMemBits = 2}); - afterAll(() => OConfig.orgMemBits = mbits); - - it("Checking getting value by constant", () => { - org.mem.splice(0, org.mem.length, ...[1,2,3,4]); - expect(ops.onFromMem(0x0b10ffff, 0, org)).toEqual(1); //v0=fromMem(); - expect(ops.vars).toEqual([1,1,2,3]); - - org.mem.splice(0, org.mem.length, ...[0,1,2,3]); - expect(ops.onFromMem(0x0b50ffff, 0, org)).toEqual(1); //v1=fromMem(); - expect(ops.vars).toEqual([1,0,2,3]); - }); - - it("Checking getting value by variable value", () => { - org.mem.splice(0, org.mem.length, ...[1,2,3,4]); - expect(ops.onFromMem(0x0b1fffff, 0, org)).toEqual(1); //v0=fromMem(); - expect(ops.vars).toEqual([2,1,2,3]); - - org.mem.splice(0, org.mem.length, ...[0,1,2,3]); - expect(ops.onFromMem(0x0b58ffff, 0, org)).toEqual(1); //v1=fromMem(); - expect(ops.vars).toEqual([2,1,2,3]); - }); - - it("Checking getting value by variable floating value", () => { - ops.vars.splice(0, ops.vars.length, ...[.1,3.2,.3,.4]); - org.mem.splice(0, org.mem.length, ...[1,2,3,4]); - expect(ops.onFromMem(0x0b1fffff, 0, org)).toEqual(1); //v0=fromMem(); - expect(ops.vars).toEqual([4,3.2,.3,.4]); - - ops.vars.splice(0, ops.vars.length, ...[.1,3.2,.3,.4]); - org.mem.splice(0, org.mem.length, ...[0,1,2,3]); - expect(ops.onFromMem(0x0b58ffff, 0, org)).toEqual(1); //v1=fromMem(); - expect(ops.vars).toEqual([.1,3,.3,.4]); - }); - - it("Checking getting value by variable value with 4 bits per var", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.mem.splice(0, org.mem.length, ...[1,2,3,4]); - expect(ops1.onFromMem(0x0b0fffff, 0, org)).toEqual(1); //v1=fromMem(); - expect(ops1.vars).toEqual([1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - - org.mem.splice(0, org.mem.length, ...[0,7,2,3]); - expect(ops1.onFromMem(0x0b51ffff, 0, org)).toEqual(1); //v5=fromMem(); - expect(ops1.vars).toEqual([1,1,2,3,4,7,6,7,8,9,10,11,12,13,14,15]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - - describe('onToMem() method', () => { - let org; - let ops; - let mbits; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - beforeAll(() => {mbits = OConfig.orgMemBits; OConfig.orgMemBits = 2}); - afterAll(() => OConfig.orgMemBits = mbits); - - it("Checking setting value by constant", () => { - org.mem.splice(0, org.mem.length, ...[1,2,3,4]); - expect(ops.onToMem(0x0b17ffff, 0, org)).toEqual(1); //toMem(v0, 3); - expect(org.mem).toEqual([1,2,3,0]); - }); - - it("Checking setting value by variable value", () => { - org.mem.splice(0, org.mem.length, ...[0,2,3,4]); - expect(ops.onToMem(0x0b1fffff, 0, org)).toEqual(1); //toMem(v0, v0); - expect(org.mem).toEqual([1,2,3,4]); - }); - - it("Checking setting value by variable value with 4 bits per var", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.mem.splice(0, org.mem.length, ...[0,2,3,4]); - expect(ops1.onToMem(0x0b1fffff, 0, org)).toEqual(1); //toMem(v0, v0); - expect(org.mem).toEqual([0,15,3,4]); + expect(ops1.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v1=stepLeft(); + expect(ops1.vars).toEqual([0,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); + expect(org.x).toBe(2); + expect(org.y).toBe(4); OConfig.codeBitsPerVar = bpv; ops1.destroy(); }); }); - describe('onMyX() method', () => { + xdescribe('onMyX() method', () => { let org; let ops; @@ -955,7 +260,7 @@ describe("client/src/organism/OperatorsDos", () => { }); }); - describe('onMyY() method', () => { + xdescribe('onMyY() method', () => { let org; let ops; @@ -994,7 +299,7 @@ describe("client/src/organism/OperatorsDos", () => { }); }); - describe('onCheckLeft() method', () => { + xdescribe('onCheckLeft() method', () => { let org; let ops; @@ -1045,160 +350,7 @@ describe("client/src/organism/OperatorsDos", () => { }); }); - describe('onCheckRight() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it('Checks right, but nothing there', () => { - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(2); - expect(y).toBe(2); - ret.ret = 0; - }); - org.x = 1; - org.y = 2; - expect(ops.onCheckRight(0x0c7fffff, 0, org)).toEqual(1); // v1=checkRight() - expect(ops.vars).toEqual([0,0,2,3]); - }); - - it('Checks right and energy there', () => { - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(2); - expect(y).toBe(2); - ret.ret = 9; - }); - org.x = 1; - org.y = 2; - expect(ops.onCheckRight(0x0c7fffff, 1, org)).toEqual(2); // v1=checkRight() - expect(ops.vars).toEqual([0,9,2,3]); - }); - - it('Checks right with 4 bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(2); - expect(y).toBe(2); - ret.ret = 9; - }); - org.x = 1; - org.y = 2; - expect(ops1.onCheckRight(0x0c7fffff, 1, org)).toEqual(2); // v7=checkRight() - expect(ops1.vars).toEqual([0,1,2,3,4,5,6,9,8,9,10,11,12,13,14,15]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - - describe('onCheckUp() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it('Checks up, but nothing there', () => { - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(1); - expect(y).toBe(1); - ret.ret = 0; - }); - org.x = 1; - org.y = 2; - expect(ops.onCheckUp(0x0c7fffff, 0, org)).toEqual(1); // v1=checkUp() - expect(ops.vars).toEqual([0,0,2,3]); - }); - - it('Checks up and energy there', () => { - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(1); - expect(y).toBe(1); - ret.ret = 9; - }); - org.x = 1; - org.y = 2; - expect(ops.onCheckUp(0x0c7fffff, 1, org)).toEqual(2); // v1=checkUp() - expect(ops.vars).toEqual([0,9,2,3]); - }); - - it('Checks up with 4 bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(1); - expect(y).toBe(1); - ret.ret = 9; - }); - org.x = 1; - org.y = 2; - expect(ops1.onCheckUp(0x0c7fffff, 1, org)).toEqual(2); // v7=checkUp() - expect(ops1.vars).toEqual([0,1,2,3,4,5,6,9,8,9,10,11,12,13,14,15]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - - describe('onCheckDown() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - - it('Checks down, but nothing there', () => { - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 0; - }); - org.x = 1; - org.y = 2; - expect(ops.onCheckDown(0x0c7fffff, 0, org)).toEqual(1); // v1=checkDown() - expect(ops.vars).toEqual([0,0,2,3]); - }); - - it('Checks down and energy there', () => { - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 9; - }); - org.x = 1; - org.y = 2; - expect(ops.onCheckDown(0x0c7fffff, 1, org)).toEqual(2); // v1=checkDown() - expect(ops.vars).toEqual([0,9,2,3]); - }); - - it('Checks right with 4 bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.on(EVENTS.CHECK_AT, (x, y, ret) => { - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 9; - }); - org.x = 1; - org.y = 2; - expect(ops1.onCheckDown(0x0c7fffff, 1, org)).toEqual(2); // v7=checkDown() - expect(ops1.vars).toEqual([0,1,2,3,4,5,6,9,8,9,10,11,12,13,14,15]); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - - describe('Checks complex DOS scripts for validness', () => { + xdescribe('Checks complex DOS scripts for validness', () => { const newWeights = [.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1,.1]; const weights = OConfig.orgOperatorWeights.slice(); let ocfg; diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index a4529a7..712f7a2 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -77,19 +77,19 @@ class Code2JS { } _onIf(num, line, ops) { - const cond = Num.getBits(num, Num.BITS_OF_VAR2, ops.CONDITION_BITS); + const cond = Num.getBits(num, Num.BITS_OF_VAR2, Operators.CONDITION_BITS); const bracket = ops.offs[line] === line ? '}' : ''; return `if(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){${bracket}`; } _onLoop(num, line, ops) { - const cond = Num.getBits(num, Num.BITS_OF_VAR2, ops.CONDITION_BITS); + const cond = Num.getBits(num, Num.BITS_OF_VAR2, Operators.CONDITION_BITS); const bracket = ops.offs[line] === line ? '}' : ''; return `while(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){${bracket}`; } _onOperator(num, line, ops) { - return `v${Num.getVar0(num)}=v${Num.getVar1(num)}${this._CONDITIONS[Num.getBits(num, Num.BITS_OF_VAR3, ops.CONDITION_BITS)]}v${Num.getVar2(num)}`; + return `v${Num.getVar0(num)}=v${Num.getVar1(num)}${this._CONDITIONS[Num.getBits(num, Num.BITS_OF_VAR3, Operators.CONDITION_BITS)]}v${Num.getVar2(num)}`; } _onFunc(num, line, ops) { diff --git a/client/src/vm/OperatorsSpec.js b/client/src/vm/OperatorsSpec.js index 8fb9d4d..d51e9bd 100644 --- a/client/src/vm/OperatorsSpec.js +++ b/client/src/vm/OperatorsSpec.js @@ -18,7 +18,7 @@ describe("client/src/vm/Operators", () => { OConfig.codeConstBits = 3; Operators.compile(); }); - afterAll(() => { + afterAll (() => { OConfig.codeBitsPerVar = cbpv; OConfig.codeConstBits = ccb; }); From 6d229dcef3c88dc2f57eea8f8eab1060a16afcbe Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 22 May 2018 20:05:44 +0300 Subject: [PATCH 42/88] added support of multi locational population creation --- client/src/manager/plugins/energy/Config.js | 4 ++-- client/src/manager/plugins/organisms/Config.js | 16 +++++----------- .../src/manager/plugins/organisms/Organisms.js | 15 ++++++++++----- .../plugins/organisms/dos/OperatorsSpec.js | 1 - client/src/share/Config.js | 3 +-- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 8fde9a6..8e23884 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -29,7 +29,7 @@ const Config = { /** * {Number} Opposite to maxValue. Minimum amount of energy dots */ - minValue: .6 * COLOR(COLOR_INDEX) * 4000, + minValue: .7 * COLOR(COLOR_INDEX) * 4000, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high energy concentration. @@ -37,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [1920 * 2, 1080 * 2, 2000, 2000] + groups: [1920 + 1920/2, 1080 * 2, 1000, 1000, 1920 * 3 - 1920/2, 1080 * 2, 1000, 1000] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index de9a8ba..ad769b1 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -97,12 +97,12 @@ 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: 0, + orgCrossoverPeriod: 500, /** * {Number} Period of iterations for creation of random organisms. Set it to 0 * to turn off this feature */ - orgRandomOrgPeriod: 0, + orgRandomOrgPeriod: 600, /** * {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 @@ -117,7 +117,7 @@ const Config = { * Eve. It means that these empty (without vm) organism were created * by operator and not by evolution. */ - orgStartEnergy: 0x6d3b4, + orgStartEnergy: 10 * 0x6d3b4, /** * {Number} Amount of energy, that grabs from organism in case of eating poison */ @@ -155,14 +155,14 @@ const Config = { /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 1000, + orgStartAmount: 4000, /** * {Array} Array of four elements: x,y,width,height. These values means * position (x,y) and square (width,height) of high density organisms area. * You may set this value to empty array to create organisms randomly in * whole world. */ - orgPosition: [1920 * 2, 1080 * 2, 2000, 2000], + orgPosition: [1920 + 1920/2, 1080 * 2, 1000, 1000, 1920 * 3 - 1920/2, 1080 * 2, 1000, 1000], /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, @@ -192,12 +192,6 @@ const Config = { * which this variable may contain. This value shouldn't be less then 2. */ codeBitsPerVar: 3, - /** - * {Number} Amount of bits, which stores maximum block length. Under block - * length we mean maximum amount of lines in one block like if, for,... - * TODO: remove this config - */ - codeBitsPerBlock: 10, /** * {Number} Amount of iterations between calls to V8 event loop. See * Manager._initLoop(), Manager.run() methods for details. diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index b59782e..6970876 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -255,14 +255,19 @@ class Organisms extends Configurable { _createPopulation() { const world = this.world; const positions = OConfig.orgPosition; - const hasPosition = positions.length > 3; + const posAmount = positions.length / 4; + const hasPosition = posAmount >= 1; this.reset(); - for (let i = 0, len = OConfig.orgStartAmount; i < len; i++) { + for (let i = 0, len = OConfig.orgStartAmount; i < len; i += posAmount) { if (hasPosition) { - const x = Helper.rand(positions[2]) + positions[0] - positions[2] / 2; - const y = Helper.rand(positions[3]) + positions[1] - positions[3] / 2; - if (world.isFree(x, y)) {this.createOrg(x, y)} + for (let j = 0; j < posAmount; j++) { + const x = Helper.rand(positions[j * 4 + 2]) + positions[j * 4] - positions[j * 4 + 2] / 2; + const y = Helper.rand(positions[j * 4 + 3]) + positions[j * 4 + 1] - positions[j * 4 + 3] / 2; + if (world.isFree(x, y)) { + this.createOrg(x, y) + } + } } else { this.createOrg(...world.getFreePos()); } diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 318be9a..ea34762 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -364,7 +364,6 @@ describe("client/src/manager/plugins/organisms/OperatorsDos", () => { beforeEach(() => { ocfg = new ConfigHelper(OConfig); ocfg.set('codeYieldPeriod', 2); - ocfg.set('codeBitsPerBlock', 8); ocfg.set('CODE_BITS_PER_OPERATOR', 8); ocfg.set('codeBitsPerVar', 2); ocfg.set('codeConstBits', 16); diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 0975e4d..2600d66 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -4,7 +4,6 @@ * * @author flatline */ -// TODO: this config should be refactored/moved to manager folder as it's part const Config = require('./../../../common/src/Config'); const QUIET_ALL = 0; @@ -67,7 +66,7 @@ ClientConfig.init({ * coordinate (height). It actual only for one instance mode (no distributed * calculations). */ - worldCyclical: false, + worldCyclical: true, /** * {Number} Speed coefficient. Between 0..1. 1 - max speed, 0 - min. */ From 35fd718c7bd03c465221bfb208a816fbe926e97c Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 22 May 2018 23:39:16 +0300 Subject: [PATCH 43/88] fixed many Code2JS translation errors --- client/src/manager/plugins/energy/Config.js | 2 +- client/src/manager/plugins/organisms/Config.js | 2 +- client/src/manager/plugins/organisms/dos/Code2JS.js | 2 +- client/src/vm/Code2JS.js | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 8e23884..a2df032 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -37,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [1920 + 1920/2, 1080 * 2, 1000, 1000, 1920 * 3 - 1920/2, 1080 * 2, 1000, 1000] + groups: [1920 + 1920/1.2, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.2, 1080 * 2, 500, 500] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ad769b1..583fa77 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -162,7 +162,7 @@ const Config = { * You may set this value to empty array to create organisms randomly in * whole world. */ - orgPosition: [1920 + 1920/2, 1080 * 2, 1000, 1000, 1920 * 3 - 1920/2, 1080 * 2, 1000, 1000], + orgPosition: [1920 + 1920/1.2, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.2, 1080 * 2, 500, 500], /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, diff --git a/client/src/manager/plugins/organisms/dos/Code2JS.js b/client/src/manager/plugins/organisms/dos/Code2JS.js index 80b4921..4ca6986 100644 --- a/client/src/manager/plugins/organisms/dos/Code2JS.js +++ b/client/src/manager/plugins/organisms/dos/Code2JS.js @@ -58,7 +58,7 @@ class Code2JS extends BaseCode2JS { _onListen(num) {return `v${Num.getVar0(num)}=listen()`} _onCheck(num) {return `v${Num.getVar0(num)}=check()`} _onMyEnergy(num) {return `v${Num.getVar0(num)}=myEnergy()`} - _onPoison(num) {return `poison()`} + _onPoison() {return `poison()`} } module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index 712f7a2..e968d1c 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -94,7 +94,7 @@ class Code2JS { _onFunc(num, line, ops) { const bracket = ops.offs[line] === line ? '}' : ''; - return `func f${ops.funcs.indexOf(line + 1)}{${bracket}`; + return `function f${ops.funcs.indexOf(line + 1)}(){${bracket}`; } _onFuncCall(num, line, ops) { @@ -103,9 +103,9 @@ class Code2JS { if (Num.getBits(num, Num.BITS_OF_VAR0, 1) === 1) { fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, ops.FUNC_NAME_BITS)}`; } else { - fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar)}`; + fn = `&v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar)}`; } - return `call ${fn}()`; + return `${fn}()`; } _onReturn() { @@ -117,11 +117,11 @@ class Code2JS { } _onToMem(num) { - return `toMem(v${Num.getVar0(num)},v${Num.getVar1(num)}`; + return `toMem(v${Num.getVar0(num)},v${Num.getVar1(num)})`; } _onFromMem(num) { - return `v${Num.getVar0(num)}=fromMem(v${Num.getVar1(num)}`; + return `v${Num.getVar0(num)}=fromMem(v${Num.getVar1(num)})`; } } From 1b1d3a894b47bbc9858c1b6813b25b94d08368d5 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 24 May 2018 23:15:59 +0300 Subject: [PATCH 44/88] speed optimizations --- client/src/manager/plugins/energy/Config.js | 4 ++-- client/src/manager/plugins/objects/Config.js | 4 ++-- client/src/manager/plugins/organisms/Config.js | 18 +++++++++--------- .../src/manager/plugins/organisms/Organism.js | 12 +++++++----- .../src/manager/plugins/organisms/Organisms.js | 2 +- .../manager/plugins/organisms/dos/Operators.js | 3 ++- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index a2df032..3828ed2 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -25,11 +25,11 @@ const Config = { /** * {Number} Maximum amount of energy dots */ - maxValue: .8 * COLOR(COLOR_INDEX) * 4000, + maxValue: .8 * COLOR(COLOR_INDEX) * 10000, /** * {Number} Opposite to maxValue. Minimum amount of energy dots */ - minValue: .7 * COLOR(COLOR_INDEX) * 4000, + minValue: .7 * COLOR(COLOR_INDEX) * 10000, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high energy concentration. diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index 141559b..443e383 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -16,11 +16,11 @@ const Config = { /** * {Number} Maximum amount of object dots */ - maxValue: .2 * 0x6d3b4 * 4000, + maxValue: .2 * 0x6d3b4 * 10000, /** * {Number} Opposite to maxValue. Minimum amount of object dots */ - minValue: .1 * 0x6d3b4 * 4000, + minValue: .1 * 0x6d3b4 * 10000, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high objects concentration. diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 583fa77..8481e8b 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -22,12 +22,12 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .001, .001, .001, .001, .001, // var, const, if, loop, operator, - .0001, .0001, .0001, .0001, // func, funcCall, return, bracket - .001, .001, // toMem, fromMem, - .00001, .1, .001, .001, .001, // lookAt, step, dir, myX, myY, - .1, .0001, .001, .001, .001, // eat, put, energy, pick, poison, - .001, .00001, .00001, .0001, .001 // rand, say, listen, check, myEnergy + .0001, .0001, .0001, .0001, .0001, // var, const, if, loop, operator, + .00001, .00001, .00001, .00001, // func, funcCall, return, bracket + .0001, .0001, // toMem, fromMem, + .000001, .01, .0001, .0001, .0001, // lookAt, step, dir, myX, myY, + .01, .00001, .0001, .0001, .0001, // eat, put, energy, pick, poison, + .0001, .000001, .000001, .00001, .0001 // rand, say, listen, check, myEnergy ], /** * {Array} Probabilities which used, when mutator decides what to do: @@ -70,7 +70,7 @@ const Config = { * mean, that new organism will not be cloned, if amount of organisms is >= * orgMaxOrgs config. */ - orgKillOnClone: true, + orgKillOnClone: false, /** * {Number} Amount of iterations between tournament. During tournament one * organism (looser) will be killed @@ -151,11 +151,11 @@ const Config = { * try to clone itself, when entire amount of organisms are equal * this value, the cloning will not happen. */ - orgMaxOrgs: 4000, + orgMaxOrgs: 10000, /** * {Number} Amount of organisms we have to create on program start */ - orgStartAmount: 4000, + orgStartAmount: 10000, /** * {Array} Array of four elements: x,y,width,height. These values means * position (x,y) and square (width,height) of high density organisms area. diff --git a/client/src/manager/plugins/organisms/Organism.js b/client/src/manager/plugins/organisms/Organism.js index 87563aa..9ca5536 100644 --- a/client/src/manager/plugins/organisms/Organism.js +++ b/client/src/manager/plugins/organisms/Organism.js @@ -119,12 +119,14 @@ class Organism extends Observer { this._iterations++; if (this.onBeforeRun() === false) {return true} const lines = this._energy > 0 ? this.onRun() : 0; - this._updateEnergy(); - if (this._energy > 0) { - this._updateClone(); + this.fire(ITERATION, lines, this); + if (this._iterations % 10 === 0) { + this._updateEnergy(); if (this._energy > 0) { - this.fire(ITERATION, lines, this); - this._energy > 0 && this._updateAge(); + this._updateClone(); + if (this._energy > 0) { + this._energy > 0 && this._updateAge(); + } } } diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 6970876..307dfbb 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -106,7 +106,7 @@ class Organisms extends Configurable { * @param {Organism} org Current organism */ onOrganism(org) { - if (org.vm === null) {return} + if (org.vm === null || !OConfig.orgKillOnClone) {return} if (this._curOldOrg === null) {this._curOldOrg = org} if (this._curOldOrg.iterations < org.iterations) {this._curOldOrg = org} this._curEnergy += org.energy; diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 8bfc55f..9778e7d 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -35,7 +35,8 @@ const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.CODE_BITS_PER_OPERATOR; - this.OPERATOR_AMOUNT = 26; + // TODO: revert this + this.OPERATOR_AMOUNT = 25; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point From b6ebdb051a4fd187d12b9b9b1046e2b8f2e5f59b Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 25 May 2018 00:51:32 +0300 Subject: [PATCH 45/88] fixed an issue with organism energy limit --- .../src/manager/plugins/organisms/dos/Operators.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 9778e7d..09abadd 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -365,13 +365,12 @@ class OperatorsDos extends Operators { const xy = energy[e]; const eat = (2**(e+1)) * Helper.getColor(EConfig.colorIndex); - if (org.energy + eat <= OConfig.orgMaxEnergy) { - org.energy += eat; - world.setDot(xy[0], xy[1], 0); - poses[xy[0]][xy[1]] = 0; - world.setDot(xy[2], xy[3], 0); - poses[xy[2]][xy[3]] = 0; - } + if (org.energy + eat > OConfig.orgMaxEnergy) {eat = org.energy + eat - OConfig.orgMaxEnergy} + org.energy += eat; + world.setDot(xy[0], xy[1], 0); + poses[xy[0]][xy[1]] = 0; + world.setDot(xy[2], xy[3], 0); + poses[xy[2]][xy[3]] = 0; return ++line; } } From cbc4fe32afef03def149c351ec613caf5cdffb4a Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 25 May 2018 01:00:38 +0300 Subject: [PATCH 46/88] fixed an issue with organism energy limit --- client/src/manager/plugins/organisms/dos/Operators.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 09abadd..5c5fd78 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -363,9 +363,9 @@ class OperatorsDos extends Operators { for (let e = 1, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e <= len; e++) { if (energy[e].length === 4) { const xy = energy[e]; - const eat = (2**(e+1)) * Helper.getColor(EConfig.colorIndex); + let eat = (2**(e+1)) * Helper.getColor(EConfig.colorIndex); - if (org.energy + eat > OConfig.orgMaxEnergy) {eat = org.energy + eat - OConfig.orgMaxEnergy} + if (org.energy + eat > OConfig.orgMaxEnergy) {eat = OConfig.orgMaxEnergy - org.energy} org.energy += eat; world.setDot(xy[0], xy[1], 0); poses[xy[0]][xy[1]] = 0; From aebf8e8c8d4e070876a8f0937fad5fed23201919 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 25 May 2018 12:01:09 +0300 Subject: [PATCH 47/88] fixed an issue with wrong entire energy calculation --- client/src/manager/plugins/energy/Config.js | 2 +- client/src/manager/plugins/organisms/Config.js | 2 +- client/src/manager/plugins/organisms/Organisms.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 3828ed2..1bd9532 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -37,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [1920 + 1920/1.2, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.2, 1080 * 2, 500, 500] + groups: [1920 + 1920/1.3, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.3, 1080 * 2, 500, 500] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 8481e8b..71a4c76 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -162,7 +162,7 @@ const Config = { * You may set this value to empty array to create organisms randomly in * whole world. */ - orgPosition: [1920 + 1920/1.2, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.2, 1080 * 2, 500, 500], + orgPosition: [1920 + 1920/1.3, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.3, 1080 * 2, 500, 500], /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, diff --git a/client/src/manager/plugins/organisms/Organisms.js b/client/src/manager/plugins/organisms/Organisms.js index 307dfbb..e24514e 100644 --- a/client/src/manager/plugins/organisms/Organisms.js +++ b/client/src/manager/plugins/organisms/Organisms.js @@ -106,10 +106,10 @@ class Organisms extends Configurable { * @param {Organism} org Current organism */ onOrganism(org) { + this._curEnergy += org.energy; if (org.vm === null || !OConfig.orgKillOnClone) {return} if (this._curOldOrg === null) {this._curOldOrg = org} if (this._curOldOrg.iterations < org.iterations) {this._curOldOrg = org} - this._curEnergy += org.energy; } addOrgHandlers(org) { From 27ead62c3ee006f3d441f7965a236862f6139769 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 25 May 2018 12:08:02 +0300 Subject: [PATCH 48/88] changed default config --- client/src/manager/plugins/energy/Config.js | 2 +- client/src/manager/plugins/organisms/Config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index 1bd9532..f267179 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -37,7 +37,7 @@ const Config = { * example all the screen will be filled by energy. As many values by four, you set as * many places with energy will be created. In case of null, grouping will be disabled. */ - groups: [1920 + 1920/1.3, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.3, 1080 * 2, 500, 500] + groups: [1920 + 1920/1.5, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.5, 1080 * 2, 500, 500] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 71a4c76..510782b 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -162,7 +162,7 @@ const Config = { * You may set this value to empty array to create organisms randomly in * whole world. */ - orgPosition: [1920 + 1920/1.3, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.3, 1080 * 2, 500, 500], + orgPosition: [1920 + 1920/1.5, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.5, 1080 * 2, 500, 500], /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, From 0e40b15f5b65bd843b9d17e39d0a4368b31c24ae Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 26 May 2018 00:48:52 +0300 Subject: [PATCH 49/88] fixed Code2JS parser --- client/src/manager/plugins/organisms/Config.js | 2 +- client/src/vm/Code2JS.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 510782b..270ca84 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -117,7 +117,7 @@ const Config = { * Eve. It means that these empty (without vm) organism were created * by operator and not by evolution. */ - orgStartEnergy: 10 * 0x6d3b4, + orgStartEnergy: 0x6d3b4, /** * {Number} Amount of energy, that grabs from organism in case of eating poison */ diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index e968d1c..a480f63 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -103,7 +103,7 @@ class Code2JS { if (Num.getBits(num, Num.BITS_OF_VAR0, 1) === 1) { fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, ops.FUNC_NAME_BITS)}`; } else { - fn = `&v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar)}`; + fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar)}`; } return `${fn}()`; } From 7ff0242c759536810ae3628be0c93b533fc40c6f Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 26 May 2018 13:44:24 +0300 Subject: [PATCH 50/88] Added visualize button to main screen #127 Removed poison command --- client/src/manager/Manager.js | 7 +- .../plugins/organisms/dos/Operators.js | 62 ++++--------- .../manager/plugins/status/charts/Charts.js | 2 +- client/src/view/Canvas.js | 87 +++++++++++++++---- 4 files changed, 91 insertions(+), 67 deletions(-) diff --git a/client/src/manager/Manager.js b/client/src/manager/Manager.js index 963ef0b..0ef83c1 100644 --- a/client/src/manager/Manager.js +++ b/client/src/manager/Manager.js @@ -23,7 +23,8 @@ 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'); +const Canvas = require('./../view/Canvas').Canvas; +const CEVENTS = require('./../view/Canvas').EVENTS; /** * {Function} Shortcut to the datetime stamp getter */ @@ -278,7 +279,9 @@ class Manager extends Observer { } _addHandlers() { - this._hasView && this._world.on(WEVENTS.DOT, this._onDot.bind(this)); + if (!this._hasView) {return} + this._world.on(WEVENTS.DOT, this._onDot.bind(this)); + this._canvas.on(CEVENTS.VISUALIZE, this._visualize.bind(this)); } _visualize(visualized = true) { diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 5c5fd78..cbe729c 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -6,17 +6,17 @@ * * @author flatline */ -const Helper = require('./../../../../../../common/src/Helper'); -const EVENTS = require('./../../../../../src/share/Events').EVENTS; -const OConfig = require('./../Config'); -const EConfig = require('./../../energy/Config'); -const Operators = require('./../../../../vm/Operators'); -const Objects = require('./../../objects/Objects'); -const Organism = require('./../../../plugins/organisms/Organism').Organism; -const Num = require('./../../../../vm/Num'); -const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; -const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; -const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; +const Helper = require('./../../../../../../common/src/Helper'); +const EVENTS = require('./../../../../../src/share/Events').EVENTS; +const OConfig = require('./../Config'); +const EConfig = require('./../../energy/Config'); +const Operators = require('./../../../../vm/Operators'); +const Objects = require('./../../objects/Objects'); +const Organism = require('./../../../plugins/organisms/Organism').Organism; +const Num = require('./../../../../vm/Num'); +const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; +const OFFSY = require('./../../../../../../common/src/Directions').OFFSY; +const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; const NORMALIZE_NO_DIR = Helper.normalizeNoDir; /** @@ -30,12 +30,14 @@ const OBJECT = 3; * {Function} Is created to speed up this function call. constants are run * much faster, then Helper.normalize() */ -const IN_WORLD = Helper.inWorld; +const IN_WORLD = Helper.inWorld; class OperatorsDos extends Operators { static compile() { const bitsPerOp = OConfig.CODE_BITS_PER_OPERATOR; - // TODO: revert this + /** + * {Number} Total amount of operators. Base lang + custom + */ this.OPERATOR_AMOUNT = 25; // // IMPORTANT: don't use super here, because it breaks Operators @@ -74,7 +76,6 @@ class OperatorsDos extends Operators { this._compileListen(); // 22 this._compileCheck(); // 23 this._compileMyEnergy(); // 24 - this._compilePoison(); // 25 } /** @@ -233,12 +234,6 @@ class OperatorsDos extends Operators { [x, y] = NORMALIZE_NO_DIR(org.dirX, org.dirY); const victim = this._positions[x][y]; - if (victim === OBJECT_TYPES.POISON) { // Poison found - this._positions[x][y] = 0; - this._world.setDot(x, y, 0); - org.destroy(); - return ++line; - } if (victim < 0) {return ++line} // World object found. We can't eat objects if (victim === 0) { // Energy found if ((eat = this._world.grabDot(x, y, eat)) > 0) { @@ -565,33 +560,6 @@ class OperatorsDos extends Operators { } } - /** - * Compiles all variants of 'poison' operator and stores they in - * this._compiledOperators map. '...' means, that all other bits are - * ignored. Poison direction depends on active organism's direction. - * See Organism.dir property. Example: - * - * bits : 6 - * number: 111001... - * string: poison - */ - static _compilePoison() { - const ops = this._compiledOperators; - const h = Helper.toHexNum; - - eval(`Operators.global.fn = function poison(line, num, org) { - let x = org.dirX; - let y = org.dirY; - if (!IN_WORLD(x, y) || this._world.data[x][y] !== 0 || org.energy <= OConfig.orgPoisonValue) {return ++line} - - this._world.setDot(x, y, Helper.getColor(OConfig.orgPoisonColor)); - this._positions[x][y] = OBJECT_TYPES.POISON; - if ((org.energy -= OConfig.orgPoisonValue) < 0) {org.destroy()} - return ++line; - }`); - ops[h(`${'111001'}`)] = this.global.fn; - } - constructor(offs, vars, obs) { super(offs, vars, obs); /** diff --git a/client/src/manager/plugins/status/charts/Charts.js b/client/src/manager/plugins/status/charts/Charts.js index 3066047..66b7541 100644 --- a/client/src/manager/plugins/status/charts/Charts.js +++ b/client/src/manager/plugins/status/charts/Charts.js @@ -90,7 +90,7 @@ class Charts extends Status { return document.body.appendChild(Helper.setStyles('DIV', { position : 'absolute', top : '7px', - left : '35px', + left : '60px', color : '#fff', fontSize : '18px', fontFamily: 'Consolas' diff --git a/client/src/view/Canvas.js b/client/src/view/Canvas.js index d9cc425..90ab9d5 100644 --- a/client/src/view/Canvas.js +++ b/client/src/view/Canvas.js @@ -3,12 +3,23 @@ * * @author flatline */ -const Panzoom = require('panzoom'); -const Helper = require('./../../../common/src/Helper'); -const Config = require('./../share/Config').Config; +const Panzoom = require('panzoom'); +const Observer = require('./../../../common/src/Observer'); +const Helper = require('./../../../common/src/Helper'); +const Config = require('./../share/Config').Config; -class Canvas { +/** + * {Number} Amount of events in canvas + */ +const EVENT_AMOUNT = 1; +const EVENT_VISUALIZE = 0; +const EVENTS = { + VISUALIZE: EVENT_VISUALIZE +}; + +class Canvas extends Observer { constructor(width, height) { + super(EVENT_AMOUNT); const id = 'world'; const doc = document; @@ -25,7 +36,9 @@ class Canvas { this._visualize = true; this._panZoom = null; this._zoomObserver = null; - this._fullEl = this._createFullScreen(); + this._fullEl = this._createFullScreenBtn(); + this._visualizeEl = this._createVisualizeBtn(); + this._isVisualizeOn = true; this._xDataOffs = 0; this._yDataOffs = 0; this._visibleWidth = Config.worldWidth; @@ -44,11 +57,13 @@ class Canvas { this._panZoom.dispose(); parentNode.removeChild(this._canvasEl); parentNode.removeChild(this._fullEl); - this._canvasEl = null; - this._fullEl = null; - this._ctx = null; - this._imgData = null; - this._data = null; + parentNode.removeChild(this._visualizeEl); + this._canvasEl = null; + this._fullEl = null; + this._visualizeEl = null; + this._ctx = null; + this._imgData = null; + this._data = null; } visualize(visualize = true) { @@ -91,7 +106,7 @@ class Canvas { data[offs + 2] = color & 0xff; } - _createFullScreen() { + _createFullScreenBtn() { const el = document.body.appendChild(Helper.setStyles('DIV', { position : 'absolute', width : '20px', @@ -103,21 +118,59 @@ class Canvas { borderRadius : '6px', cursor : 'pointer' })); + // + // Inner div + // + const innerEl = document.body.appendChild(Helper.setStyles('DIV', { + position : 'absolute', + width : '10px', + height : '10px', + top : '12px', + left : '12px', + border : '1px #000 solid', + backgroundColor: '#f7ed0e', + borderRadius : '3px', + cursor : 'pointer' + })); + + el.title = 'fullscreen'; + el.onclick = this._onFullscreen.bind(this); + innerEl.onclick = this._onFullscreen.bind(this); + + return el; + } + + _createVisualizeBtn() { + const el = document.body.appendChild(Helper.setStyles('DIV', { + position : 'absolute', + width : '20px', + height : '20px', + top : '7px', + left : '34px', + border : '1px #000 solid', + backgroundColor: '#b30729', + borderRadius : '6px', + cursor : 'pointer' + })); + + el.title = 'visualize'; + el.onclick = this._onVisualize.bind(this); - el.title = 'fullscreen'; - // TODO: use addEventListener(). - el.onclick = this._onFullscreen.bind(this); - return el; } _onFullscreen() { this._panZoom.zoomAbs(0, 0, 1.0); this._panZoom.moveTo(0, 0); - this._canvasEl.style.width = '100%'; + this._canvasEl.style.width = '100%'; this._canvasEl.style .height = '100%'; } + _onVisualize() { + this.fire(EVENT_VISUALIZE, this._isVisualizeOn = !this._isVisualizeOn); + this._visualizeEl.style.backgroundColor = this._isVisualizeOn ? '#b30729' : '#ccc'; + } + _onAnimate() { this._ctx.putImageData(this._imgData, 0, 0, this._xDataOffs, this._yDataOffs, this._visibleWidth, this._visibleHeight); @@ -201,4 +254,4 @@ class Canvas { } } -module.exports = Canvas; \ No newline at end of file +module.exports = {Canvas, EVENTS}; \ No newline at end of file From 4b5c53bb9583c9ac14c3ca549854b2abacf93478 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 26 May 2018 16:29:29 +0300 Subject: [PATCH 51/88] Added visualize button hot key (Ctrl-F, Ctrl-V) #127 --- client/src/view/Canvas.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/client/src/view/Canvas.js b/client/src/view/Canvas.js index 90ab9d5..3e7ef5a 100644 --- a/client/src/view/Canvas.js +++ b/client/src/view/Canvas.js @@ -147,9 +147,11 @@ class Canvas extends Observer { height : '20px', top : '7px', left : '34px', - border : '1px #000 solid', - backgroundColor: '#b30729', + border : '1px #FFEB3B solid', + backgroundSize : '8px 8px', borderRadius : '6px', + background : 'radial-gradient(#F44336 15%, transparent 16%) 0 0, radial-gradient(#F44336 15%, transparent 16%) 4px 4px, radial-gradient(rgba(255,255,253,.1) 15%, transparent 20%) 0 1px, radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 8px 8px', + backgroundColor: '#FFEB3B', cursor : 'pointer' })); @@ -168,7 +170,7 @@ class Canvas extends Observer { _onVisualize() { this.fire(EVENT_VISUALIZE, this._isVisualizeOn = !this._isVisualizeOn); - this._visualizeEl.style.backgroundColor = this._isVisualizeOn ? '#b30729' : '#ccc'; + this._visualizeEl.style.backgroundColor = this._isVisualizeOn ? '#FFEB3B' : '#000'; } _onAnimate() { @@ -211,6 +213,22 @@ class Canvas extends Observer { childList : false, attributeFilter: ['style'] }); + // + // Global keyup event handler + // + document.addEventListener('keydown', this._onKeyDown.bind(this)); + } + + _onKeyDown(event) { + if (event.ctrlKey && (event.key === 'V' || event.key === 'v')){ + this._onVisualize(); + event.preventDefault(); + return false; + } else if (event.ctrlKey && (event.key === 'F' || event.key === 'f')) { + this._onFullscreen(); + event.preventDefault(); + return false; + } } /** From ff0adc9625c5bf9f075ca5142aa15454194e4232 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 27 May 2018 23:30:04 +0300 Subject: [PATCH 52/88] operator rend() has moved to base language added operator myAge() --- README.md | 2 +- .../manager/plugins/organisms/dos/Code2JS.js | 28 ++--- .../plugins/organisms/dos/Operators.js | 119 +++++++++--------- .../plugins/organisms/garmin/Code2String.js | 2 +- .../plugins/organisms/garmin/Organisms.js | 4 +- client/src/vm/Code2JS.js | 7 +- client/src/vm/Operators.js | 33 ++++- 7 files changed, 113 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index 8c5723b..7f0dd14 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ 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.toJS(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()`. diff --git a/client/src/manager/plugins/organisms/dos/Code2JS.js b/client/src/manager/plugins/organisms/dos/Code2JS.js index 4ca6986..47f5a7f 100644 --- a/client/src/manager/plugins/organisms/dos/Code2JS.js +++ b/client/src/manager/plugins/organisms/dos/Code2JS.js @@ -18,25 +18,24 @@ class Code2JS extends BaseCode2JS { * {Object} These operator handlers should return string representation * of numeric based byte vm. */ - this.operators[0b101011] = this._onLookAt.bind(this); - this.operators[0b101100] = this._onStep.bind(this); - this.operators[0b101101] = this._onDir.bind(this); - this.operators[0b101110] = this._onMyX.bind(this); - this.operators[0b101111] = this._onMyY.bind(this); - this.operators[0b110000] = this._onEat.bind(this); - this.operators[0b110001] = this._onPut.bind(this); - this.operators[0b110010] = this._onEnergy.bind(this); - this.operators[0b110011] = this._onPick.bind(this); - this.operators[0b110100] = this._onRand.bind(this); + this.operators[0b101100] = this._onLookAt.bind(this); + this.operators[0b101101] = this._onStep.bind(this); + this.operators[0b101110] = this._onDir.bind(this); + this.operators[0b101111] = this._onMyX.bind(this); + this.operators[0b110000] = this._onMyY.bind(this); + this.operators[0b110001] = this._onEat.bind(this); + this.operators[0b110010] = this._onPut.bind(this); + this.operators[0b110011] = this._onEnergy.bind(this); + this.operators[0b110100] = this._onPick.bind(this); this.operators[0b110101] = this._onSay.bind(this); this.operators[0b110110] = this._onListen.bind(this); this.operators[0b110111] = this._onCheck.bind(this); this.operators[0b111000] = this._onMyEnergy.bind(this); - this.operators[0b111001] = this._onPoison.bind(this); + this.operators[0b111001] = this._onMyAge.bind(this); // // API of the Manager for accessing outside. (e.g. from Console) // - 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.'); + Helper.setApi(manager.api, 'toJS', (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.toJS(man.api.organisms.getOrganism(\'128\').vm.code). This example will find organism with id \'128\' and shows his byte code.'); } destroy() { @@ -51,14 +50,13 @@ class Code2JS extends BaseCode2JS { _onMyY(num) {return `v${Num.getVar0(num)}=myY()`} _onEat(num) {return `eat(v${Num.getVar0(num)})`} _onPut(num) {return `put(v${Num.getVar0(num)})`} - _onEnergy(num) {return `energy(v${Num.getVar0(num)})`} + _onEnergy(num) {return `energy()`} _onPick(num) {return `pick(v${Num.getVar0(num)})`} - _onRand(num) {return `v${Num.getVar0(num)}=rand(v${Num.getVar1(num)})`} _onSay(num) {return `say(v${Num.getVar0(num)})`} _onListen(num) {return `v${Num.getVar0(num)}=listen()`} _onCheck(num) {return `v${Num.getVar0(num)}=check()`} _onMyEnergy(num) {return `v${Num.getVar0(num)}=myEnergy()`} - _onPoison() {return `poison()`} + _onMyAge(num) {return `v${Num.getVar0(num)}=myAge()`} } module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index cbe729c..a3b548f 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -38,7 +38,7 @@ class OperatorsDos extends Operators { /** * {Number} Total amount of operators. Base lang + custom */ - this.OPERATOR_AMOUNT = 25; + this.OPERATOR_AMOUNT = 26; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -61,21 +61,22 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - bitsPerOp); + this.LENS.push(Num.MAX_BITS - bitsPerOp); - this._compileLookAt(); // 11 - this._compileStep(); // 12 - this._compileDir(); // 13 - this._compileMyX(); // 14 - this._compileMyY(); // 15 - this._compileEat(); // 16 - this._compilePut(); // 17 - this._compileEnergy(); // 18 - this._compilePick(); // 19 - this._compileRand(); // 20 + this._compileLookAt(); // 12 + this._compileStep(); // 13 + this._compileDir(); // 14 + this._compileMyX(); // 15 + this._compileMyY(); // 16 + this._compileEat(); // 17 + this._compilePut(); // 18 + this._compileEnergy(); // 19 + this._compilePick(); // 20 this._compileSay(); // 21 this._compileListen(); // 22 this._compileCheck(); // 23 this._compileMyEnergy(); // 24 + this._compileMyAge(); // 25 } /** @@ -85,7 +86,7 @@ class OperatorsDos extends Operators { * ignored. Example: * * bits : 6 xx xx xx - * number: 101011 00 01 00... + * number: 101100 00 01 00... * string: v0 = lookAt(v1, v0) */ static _compileLookAt() { @@ -105,7 +106,7 @@ class OperatorsDos extends Operators { vars[${v0}] = (IN_WORLD(x, y) ? (this._positions[x][y] <= 0 ? this._world.data[x][y] : this._positions[x][y].energy) : 0); return ++line; }`); - ops[h(`${'101011'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}`)] = this.global.fn; + ops[h(`${'101100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}`)] = this.global.fn; } } } @@ -118,7 +119,7 @@ class OperatorsDos extends Operators { * See Organism.dir property. Example: * * bits : 6 - * number: 101100... + * number: 101101... * string: step */ static _compileStep() { @@ -126,7 +127,7 @@ class OperatorsDos extends Operators { this._obs.fire(${EVENTS.STEP}, org, org.x, org.y, org.dirX, org.dirY); return ++line; }`); - this._compiledOperators[Helper.toHexNum(`${'101100'}`)] = this.global.fn; + this._compiledOperators[Helper.toHexNum(`${'101101'}`)] = this.global.fn; } /** @@ -136,7 +137,7 @@ class OperatorsDos extends Operators { * ignored. Example: * * bits : 6 xx - * number: 101101 11... + * number: 101110 11... * string: dir(v3) */ static _compileDir() { @@ -152,7 +153,7 @@ class OperatorsDos extends Operators { org.dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; return ++line; }`); - ops[h(`${'101101'}${b(v0, bpv)}`)] = this.global.fn; + ops[h(`${'101110'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -163,7 +164,7 @@ class OperatorsDos extends Operators { * ignored. Example: * * bits : 6 xx - * number: 101110 00... + * number: 101111 00... * string: v0 = myX() */ static _compileMyX() { @@ -178,7 +179,7 @@ class OperatorsDos extends Operators { this.vars[${v0}] = org.x; return ++line; }`); - ops[h(`${'101110'}${b(v0, bpv)}`)] = this.global.fn; + ops[h(`${'101111'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -189,7 +190,7 @@ class OperatorsDos extends Operators { * ignored. Example: * * bits : 6 xx - * number: 101111 00... + * number: 110000 00... * string: v0 = myY() */ static _compileMyY() { @@ -204,7 +205,7 @@ class OperatorsDos extends Operators { this.vars[${v0}] = org.y; return ++line; }`); - ops[h(`${'101111'}${b(v0, bpv)}`)] = this.global.fn; + ops[h(`${'110000'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -215,7 +216,7 @@ class OperatorsDos extends Operators { * See Organism.dir property. Example: * * bits : 6 xx - * number: 110000 01... + * number: 110001 01... * string: eat(v1) */ static _compileEat() { @@ -264,7 +265,7 @@ class OperatorsDos extends Operators { return ++line; }`); - ops[h(`${'110000'}${b(v0, bpv)}`)] = this.global.fn; + ops[h(`${'110001'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -275,7 +276,7 @@ class OperatorsDos extends Operators { * See Organism.dir property. Example: * * bits : 6 xx - * number: 110001 01... + * number: 110010 01... * string: put(v1) */ static _compilePut() { @@ -309,7 +310,7 @@ class OperatorsDos extends Operators { org.energy -= put; return ++line; }`); - ops[h(`${'110001'}${b(v0, bpv)}`)] = this.global.fn; + ops[h(`${'110010'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -321,9 +322,9 @@ class OperatorsDos extends Operators { * only one energy object it will not be transformed to energy. * Example: * - * bits : 6 xx - * number: 110010 01... - * string: energy(v1) + * bits : 6 + * number: 110011... + * string: energy() */ static _compileEnergy() { const ops = this._compiledOperators; @@ -371,7 +372,7 @@ class OperatorsDos extends Operators { } return ++line; }`); - ops[h(`${'110010'}`)] = this.global.fn; + ops[h(`${'110011'}`)] = this.global.fn; } /** @@ -381,7 +382,7 @@ class OperatorsDos extends Operators { * See Organism.dir property. Example: * * bits : 6 xx - * number: 110011 01... + * number: 110100 01... * string: pick(v1) */ static _compilePick() { @@ -411,35 +412,7 @@ class OperatorsDos extends Operators { } return ++line; }`); - ops[h(`${'110011'}${b(v0, bpv)}`)] = this.global.fn; - } - } - - /** - * Compiles all variants of 'rand' operator and stores they in - * this._compiledOperators map. '...' means, that all other bits are - * ignored. Step direction depends on active organism's direction. - * See Organism.dir property. Example: - * - * bits : 6 xx xx - * number: 110100 01 11... - * string: v1 = rand(v3) - */ - static _compileRand() { - const bpv = OConfig.codeBitsPerVar; - const ops = this._compiledOperators; - const h = Helper.toHexNum; - const b = Helper.toBinStr; - const vars = Math.pow(2, bpv); - - for (let v0 = 0; v0 < vars; v0++) { - for (let v1 = 0; v1 < vars; v1++) { - eval(`Operators.global.fn = function rand(line) { - this.vars[${v0}] = Helper.rand(((this.vars[${v1}] + .5) << 0 >>> 0)); - return ++line; - }`); - ops[h(`${'110100'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; - } + ops[h(`${'110100'}${b(v0, bpv)}`)] = this.global.fn; } } @@ -535,7 +508,7 @@ class OperatorsDos extends Operators { } /** - * Compiles all variants of 'check' operator and stores they in + * Compiles all variants of 'myEnergy' operator and stores they in * this._compiledOperators map. '...' means, that all other bits are * ignored. Step direction depends on active organism's direction. * See Organism.dir property. Example: @@ -560,6 +533,32 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'myAge' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 111001 00... + * string: v0 = myAge() + */ + static _compileMyAge() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = Helper.toHexNum; + const b = Helper.toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function myEnergy(line, num, org) { + this.vars[${v0}] = org.iterations; + return ++line; + }`); + ops[h(`${'111001'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** diff --git a/client/src/manager/plugins/organisms/garmin/Code2String.js b/client/src/manager/plugins/organisms/garmin/Code2String.js index 5f2b49f..8a2dde7 100644 --- a/client/src/manager/plugins/organisms/garmin/Code2String.js +++ b/client/src/manager/plugins/organisms/garmin/Code2String.js @@ -53,7 +53,7 @@ class Code2JS { // // API of the Manager for accessing outside. (e.g. from Console) // - manager.api.formatCode = (code) => this.format(code); + manager.api.toJS = (code) => this.format(code); } destroy() { diff --git a/client/src/manager/plugins/organisms/garmin/Organisms.js b/client/src/manager/plugins/organisms/garmin/Organisms.js index 8a584f1..f8fd4bd 100644 --- a/client/src/manager/plugins/organisms/garmin/Organisms.js +++ b/client/src/manager/plugins/organisms/garmin/Organisms.js @@ -41,7 +41,7 @@ class Organisms extends BaseOrganisms { Console.warn('--------------------------------------------------'); Console.warn('Max energy: ', org.energy, ', org Id: ', org.id); Console.warn('[' + org.vm.code + ']'); - Console.warn(this.manager.api.formatCode(org.vm.code)); + Console.warn(this.manager.api.toJS(org.vm.code)); } if (org.changes > this._maxChanges) {this._maxChanges = org.changes} @@ -75,7 +75,7 @@ class Organisms extends BaseOrganisms { Console.warn('--------------------------------------------------'); Console.warn('org id: ', org.id, ', energy: ', org.energy); Console.warn('[' + org.vm.code + ']'); - Console.warn(this.manager.api.formatCode(org.vm.code)); + Console.warn(this.manager.api.toJS(org.vm.code)); } } diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index a480f63..c811522 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -33,7 +33,8 @@ class Code2JS { 0b100111: this._onReturn.bind(this), 0b101000: this._onBracket.bind(this), 0b101001: this._onToMem.bind(this), - 0b101010: this._onFromMem.bind(this) + 0b101010: this._onFromMem.bind(this), + 0b101011: this._onRand.bind(this) }; } @@ -123,6 +124,10 @@ class Code2JS { _onFromMem(num) { return `v${Num.getVar0(num)}=fromMem(v${Num.getVar1(num)})`; } + + _onRand(num) { + return `v${Num.getVar0(num)}=rand(v${Num.getVar1(num)})`; + } } module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 7aa35fe..1d49614 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -8,7 +8,7 @@ const OConfig = require('./../manager/plugins/organisms/Config'); const Num = require('./Num'); const Helper = require('./../../../common/src/Helper'); -const OPERATOR_AMOUNT = 11; +const OPERATOR_AMOUNT = 12; const MAX_STACK_SIZE = 30000; class Operators { @@ -64,7 +64,7 @@ class Operators { MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar), // const MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2 + this.CONDITION_BITS), // if MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2 + this.CONDITION_BITS), // loop - MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3 + this.CONDITION_BITS), // math + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3 + this.CONDITION_BITS), // math MAX_BITS - (bitsPerOp), // func MAX_BITS - (bitsPerOp), // func call MAX_BITS - (bitsPerOp), // return @@ -93,6 +93,7 @@ class Operators { this._compileBracket(); // 8 this._compileToMem(); // 9 this._compileFromMem(); // 10 + this._compileRand(); // 11 } /** @@ -423,6 +424,34 @@ class Operators { } } + /** + * Compiles all variants of 'rand' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx xx + * number: 101011 01 11... + * string: v1 = rand(v3) + */ + static _compileRand() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = Helper.toHexNum; + const b = Helper.toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + for (let v1 = 0; v1 < vars; v1++) { + eval(`Operators.global.fn = function rand(line) { + this.vars[${v0}] = Helper.rand(((this.vars[${v1}] + .5) << 0 >>> 0)); + return ++line; + }`); + ops[h(`${'101011'}${b(v0, bpv)}${b(v1, bpv)}`)] = this.global.fn; + } + } + } + constructor(offs, vars) { this._MAX_FUNC_AMOUNT = Math.pow(2, Operators.FUNC_NAME_BITS); /** From 659468d214b16186a31dfaa1e49b7255476f8f73 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 5 Jun 2018 08:35:40 +0300 Subject: [PATCH 53/88] tests... --- client/src/manager/plugins/energy/Config.js | 9 +- client/src/manager/plugins/energy/Energy.js | 27 +- client/src/manager/plugins/objects/Config.js | 8 +- client/src/manager/plugins/objects/Objects.js | 21 ++ .../src/manager/plugins/organisms/Config.js | 21 +- .../plugins/organisms/dos/Operators.js | 36 +- .../plugins/organisms/dos/OperatorsSpec.js | 308 +++++++++++------- client/src/share/Config.js | 10 + client/src/vm/Operators.js | 3 +- tests/jasmine.json | 5 +- 10 files changed, 293 insertions(+), 155 deletions(-) diff --git a/client/src/manager/plugins/energy/Config.js b/client/src/manager/plugins/energy/Config.js index f267179..5386d96 100644 --- a/client/src/manager/plugins/energy/Config.js +++ b/client/src/manager/plugins/energy/Config.js @@ -4,9 +4,8 @@ * @author flatline */ const Helper = require('./../../../../../common/src/Helper'); +const GConfig = require('./../../../share/Config').Config; -const COLOR_INDEX = 10000; -const COLOR = Helper.getColor; const Config = { /** * {Number} An amount of iteration, after which we have to check world energy @@ -21,15 +20,15 @@ const Config = { * {Number} Index of energy color. Starts from 0. Ends with 4000. See Organism.MAX_COLORS * constant for details */ - colorIndex: COLOR_INDEX, + colorIndex: GConfig.worldEnergyColor, /** * {Number} Maximum amount of energy dots */ - maxValue: .8 * COLOR(COLOR_INDEX) * 10000, + maxValue: .8 * GConfig.worldEnergy, /** * {Number} Opposite to maxValue. Minimum amount of energy dots */ - minValue: .7 * COLOR(COLOR_INDEX) * 10000, + minValue: .7 * GConfig.worldEnergy, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high energy concentration. diff --git a/client/src/manager/plugins/energy/Energy.js b/client/src/manager/plugins/energy/Energy.js index f799641..8e8a15b 100644 --- a/client/src/manager/plugins/energy/Energy.js +++ b/client/src/manager/plugins/energy/Energy.js @@ -5,14 +5,39 @@ */ const Dots = require('./../../../share/Dots'); const EConfig = require('./Config'); +const Helper = require('./../../../../../common/src/Helper'); +const EVENTS = require('./../../../share/Events').EVENTS; class Energy extends Dots { constructor(manager) { super(manager, EConfig, { addOnce : false, compareCb: (x,y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] === 0, - checkMin : (val) => val + manager.sharedObj.orgEnergy < this.config.minValue + checkMin : (val) => val + manager.sharedObj.orgEnergy + manager.sharedObj.objectsEnergy < EConfig.minValue }); + this._color = Helper.getColor(EConfig.colorIndex); + this._energy = 0; + this._sharedObj = manager.sharedObj; + this._sharedObj.energy = 0; + } + + onIteration(counter) { + const energy = super.onIteration(counter); + if (energy !== false) { + this.manager.fire(EVENTS.WORLD_ENERGY, energy / this._color); + this._energy = energy; + } + } + + /** + * Override of Manager.onLoop() method. Stores amount of energy in sharedObj + * @param {Number} counter Global counter. Time analog + * @param {Number} stamp Time stamp + * @param {Object} sharedObj Shared object of the manager + */ + onLoop(counter, stamp, sharedObj) { + super.onLoop(counter, stamp, sharedObj); + sharedObj.energy = this._energy; } } diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index 443e383..e18d12d 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -3,7 +3,9 @@ * * @author flatline */ -const Config = { +const GConfig = require('./../../../share/Config').Config; + +const Config = { /** * {Number} An amount of iteration, after which we have to check world energy * objects percent. May be 0 if you want to disable energy objects generation @@ -16,11 +18,11 @@ const Config = { /** * {Number} Maximum amount of object dots */ - maxValue: .2 * 0x6d3b4 * 10000, + maxValue: .8 * GConfig.worldEnergy, /** * {Number} Opposite to maxValue. Minimum amount of object dots */ - minValue: .1 * 0x6d3b4 * 10000, + minValue: .7 * GConfig.worldEnergy, /** * {Array|null} In case of array you may set sequence of four values: x,y,w,h. * They means x,y coordinates, width, height of places with high objects concentration. diff --git a/client/src/manager/plugins/objects/Objects.js b/client/src/manager/plugins/objects/Objects.js index 022fdfd..475512b 100644 --- a/client/src/manager/plugins/objects/Objects.js +++ b/client/src/manager/plugins/objects/Objects.js @@ -31,8 +31,29 @@ class Objects extends Dots { addOnce : false, compareCb : (x, y) => manager.world.getDot(x, y) > 0 && manager.positions[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 && manager.positions[x][y] <= OBJECT_TYPES.TYPE_ENERGY0, colorCb : ( ) => COLOR_RGB, + checkMin : (val ) => val + manager.sharedObj.orgEnergy + manager.sharedObj.energy < OConfig.minValue, setCb : (x, y) => manager.positions[x][y] = COLOR_INDEX }); + this._energy = 0; + this._sharedObj = manager.sharedObj; + this._sharedObj.objectsEnergy = 0; + } + + onIteration(counter) { + const energy = super.onIteration(counter); + if (energy !== false) { + this._energy = energy; + } + } + /** + * Override of Manager.onLoop() method. Stores amount of energy in sharedObj + * @param {Number} counter Global counter. Time analog + * @param {Number} stamp Time stamp + * @param {Object} sharedObj Shared object of the manager + */ + onLoop(counter, stamp, sharedObj) { + super.onLoop(counter, stamp, sharedObj); + sharedObj.objectsEnergy = this._energy; } } diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 270ca84..3145d1f 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -3,7 +3,12 @@ * * @author flatline */ -const Config = { +const Helper = require('./../../../../../common/src/Helper'); +const GConfig = require('./../../../share/Config').Config; + +const ENERGY_VALUE = Helper.getColor(GConfig.worldEnergyColor); + +const Config = { /** * @constant * {Number} Max value, which we may use in orgMutationProbs array. We may use @@ -63,7 +68,7 @@ const Config = { /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: .8 * 0x6d3b4, + orgCloneMinEnergy: .8 * ENERGY_VALUE, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -111,21 +116,13 @@ const Config = { /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: 0x6d3b4, + orgMaxEnergy: ENERGY_VALUE, /** * {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: 0x6d3b4, - /** - * {Number} Amount of energy, that grabs from organism in case of eating poison - */ - orgPoisonValue: .5 * 0x6d3b4, - /** - * {Number} Color index of poison dot - */ - orgPoisonColor: 6645, + orgStartEnergy: ENERGY_VALUE, /** * {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/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index a3b548f..e03f4fe 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -55,13 +55,11 @@ class OperatorsDos extends Operators { this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - bitsPerOp); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // say this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - bitsPerOp); - this.LENS.push(Num.MAX_BITS - bitsPerOp); this._compileLookAt(); // 12 this._compileStep(); // 13 @@ -103,7 +101,11 @@ class OperatorsDos extends Operators { const vars = this.vars; const x = (vars[${v1}] + .5) << 0; const y = (vars[${v2}] + .5) << 0; - vars[${v0}] = (IN_WORLD(x, y) ? (this._positions[x][y] <= 0 ? this._world.data[x][y] : this._positions[x][y].energy) : 0); + if (!IN_WORLD(x, y)) { + vars[${v0}] = 0; + return ++line; + } + vars[${v0}] = this._getDotType(x, y); return ++line; }`); ops[h(`${'101100'}${b(v0, bpv)}${b(v1, bpv)}${b(v2, bpv)}`)] = this.global.fn; @@ -492,14 +494,7 @@ class OperatorsDos extends Operators { const x = org.dirX; const y = org.dirY; if (!IN_WORLD(x, y)) {return ++line} - - if (this._positions[x][y] < 0) { - this.vars[${v0}] = this._positions[x][y]; - } else if (this._positions[x][y] === 0) { - this.vars[${v0}] = this._world.getDot(x, y) > 0 ? ENERGY : EMPTY; - } else { - this.vars[${v0}] = ORGANISM; - } + this.vars[${v0}] = this._getDotType(x, y); return ++line; }`); @@ -575,6 +570,23 @@ class OperatorsDos extends Operators { */ get length() {return OperatorsDos.OPERATOR_AMOUNT} + /** + * Returns type of the dot under x,y coordinates + * @param {Number} x X coordinate + * @param {Number} y Y coordinate + * @returns {Number} dot type + */ + _getDotType(x, y) { + if (this._positions[x][y] < 0) { + return this._positions[x][y]; + } + if (this._positions[x][y] === 0) { + return this._world.getDot(x, y) > 0 ? ENERGY : EMPTY; + } + + return ORGANISM; + } + destroy() { super.destroy(); diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index ea34762..8e38dc4 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1,106 +1,233 @@ -const _fill = require('lodash/fill'); -const Operators = require('./Operators'); -const OConfig = require('./../../../plugins/organisms/Config'); -const Helper = require('./../../../../../../common/src/Helper'); - -describe("client/src/manager/plugins/organisms/OperatorsDos", () => { - const h = Helper.toHexNum; - const MAX_NUM = Number.MAX_VALUE; +const _fill = require('lodash/fill'); +const OperatorsDos = require('./Operators'); +const OConfig = require('./../../../plugins/organisms/Config'); +const Config = require('./../../../../share/Config').Config; +const Helper = require('./../../../../../../common/src/Helper'); +const OrganismDos = require('./Organism'); +const World = require('./../../../../view/World').World; + +describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { + const hex = Helper.toHexNum; + const ww = Config.worldWidth; + const wh = Config.worldHeight; + const oldMan = global.man; let cbpv; let ccb; let ops; let offs; let vars; + let w; + let h; beforeAll (() => { cbpv = OConfig.codeBitsPerVar; OConfig.codeBitsPerVar = 2; ccb = OConfig.codeConstBits; OConfig.codeConstBits = 3; - Operators.compile(); + global.man = {world: {}, positions: [ + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0], + [0,0,0,0,0,0,0,0,0,0] + ]}; + OperatorsDos.compile(); }); afterAll (() => { OConfig.codeBitsPerVar = cbpv; OConfig.codeConstBits = ccb; + global.man = oldMan; }); beforeEach(() => { - vars = [0,1,2,3]; - offs = new Array(10); - ops = new Operators(offs, vars); + w = 10; + h = 10; + Config.worldWidth = w; + Config.worldHeight = h; + global.man.world = new World(w, h); + vars = [0,1,2,3]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars); }); afterEach (() => { ops.destroy(); - ops = null; - offs = null; - vars = null; + global.man.world.destroy(); + ops = null; + offs = null; + vars = null; + Config.worldWidth = ww; + Config.worldHeight = wh; }); - xdescribe('onLookAt() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - + describe('onLookAt() method', () => { it("Checking onLookAt() is found nothing", () => { - org.on(EVENTS.GET_ENERGY, (x, y, ret) => { - expect(x).toBe(2); - expect(y).toBe(3); - ret.ret = 0; - }); - expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,0,2,3]); }); - it("Checking onLookAt() looking outside of the world", () => { - ops.vars = [0, 1, 20, 30]; - expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); - expect(ops.vars).toEqual([0,0,20,30]); + it("Checking onLookAt() looking outside of the world - x", () => { + ops.vars[0] = 11; + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([11,0,2,3]); + }); - ops.vars = [0, 1, -20, -30]; - expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); - expect(ops.vars).toEqual([0,0,-20,-30]); + it("Checking onLookAt() looking outside of the world - y", () => { + ops.vars[3] = 11; + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,0,2,11]); }); it('Checking onLookAt() found an energy', () => { - org.on(EVENTS.GET_ENERGY, (x, y, ret) => { - expect(x).toBe(2); - expect(y).toBe(3); - ret.ret = 13; + global.man.world.setDot(0,3,0xaabbcc); + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3]); + global.man.world.setDot(0,3,0); + }); + + it('Checking onLookAt() found an object', () => { + global.man.world.setDot(0,3,0xaabbcc); + global.man.positions[0][3] = -2; + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,-2,2,3]); + global.man.world.setDot(0,3,0); + global.man.positions[0][3] = 0; + }); + + it('Checking onLookAt() found an organism', () => { + global.man.world.setDot(0,3,0xaabbcc); + global.man.positions[0][3] = {energy: 123}; + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,2,2,3]); + global.man.world.setDot(0,3,0); + global.man.positions[0][3] = 0; + }); + + it('Checking onLookAt() with floating coordinates', () => { + ops.vars[0] = .1; + ops.vars[3] = .2; + expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([.1,0,2,.2]); + }); + + describe('onLookAt() method 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll (() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking onLookAt() is found nothing", () => { + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,0,2,3,4,5,6,7]); + }); + + it("Checking onLookAt() looking outside of the world - x", () => { + ops.vars[0] = 11; + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([11,0,2,3,4,5,6,7]); + }); + + it("Checking onLookAt() looking outside of the world - y", () => { + ops.vars[3] = 11; + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,0,2,11,4,5,6,7]); + }); + + it('Checking onLookAt() found an energy', () => { + global.man.world.setDot(0,3,0xaabbcc); + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + global.man.world.setDot(0,3,0); }); - expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); - expect(ops.vars).toEqual([0,13,2,3]); + + it('Checking onLookAt() found an object', () => { + global.man.world.setDot(0,3,0xaabbcc); + global.man.positions[0][3] = -2; + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,-2,2,3,4,5,6,7]); + global.man.world.setDot(0,3,0); + global.man.positions[0][3] = 0; + }); + + it('Checking onLookAt() found an organism', () => { + global.man.world.setDot(0,3,0xaabbcc); + global.man.positions[0][3] = {energy: 123}; + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,2,2,3,4,5,6,7]); + global.man.world.setDot(0,3,0); + global.man.positions[0][3] = 0; + }); + + it('Checking onLookAt() with floating coordinates', () => { + ops.vars[0] = .1; + ops.vars[3] = .2; + expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([.1,0,2,.2,4,5,6,7]); + }); + }); + }); + + describe('onStepLeft() method', () => { + it("Checking step left", () => { + ops.vars[3] = 11; + ops. + expect(ops.operators[hex('101101')].call(ops, 0)).toEqual(1); + expect(ops.vars).toEqual([0,0,2,11]); + }); + + xit("Checking step left with no free space on the left", () => { + org.x = 3; + org.y = 4; + org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { + expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); + }); + expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); + expect(ops.vars).toEqual([0,1,2,3]); + expect(org.x).toBe(3); + expect(org.y).toBe(4); }); - it('Checking onLookAt() with 4 bits per var', () => { + xit("Checking step left with 4 bits per var", () => { let bpv = OConfig.codeBitsPerVar; OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,7], org); + let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - org.on(EVENTS.GET_ENERGY, (x, y, ret) => { - expect(x).toBe(7); - expect(y).toBe(7); - ret.ret = 13; + org.x = 3; + org.y = 4; + org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { + org.x = x2; + org.y = y2; + expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); }); - expect(ops1.onLookAt(0x056fffff, 0, org)).toEqual(1); //v6=lookAt(v15,v15); - expect(ops1.vars).toEqual([0,1,2,3,4,5,13,7,8,9,10,11,12,13,14,7]); + expect(ops1.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v1=stepLeft(); + expect(ops1.vars).toEqual([0,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); + expect(org.x).toBe(2); + expect(org.y).toBe(4); OConfig.codeBitsPerVar = bpv; ops1.destroy(); }); - - it('Checking onLookAt() with floating coordinates', () => { - org.on(EVENTS.GET_ENERGY, (x, y, ret) => { - expect(x).toBe(0); - expect(y).toBe(4); - ret.ret = 13; - }); - ops.vars = [0, 1, .1, 3.6]; - expect(ops.onLookAt(0x056fffff, 0, org)).toEqual(1); //v1=lookAt(v2,v3); - expect(ops.vars).toEqual([0,13,.1,3.6]); - }); }); xdescribe('onEatLeft() method', () => { @@ -164,63 +291,6 @@ describe("client/src/manager/plugins/organisms/OperatorsDos", () => { }) }); - xdescribe('onStepLeft() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; - - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); - - it("Checking step left", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); - }); - expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); - expect(ops.vars).toEqual([2,1,2,3]); - expect(org.x).toBe(2); - expect(org.y).toBe(4); - }); - - it("Checking step left with no free space on the left", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); - }); - expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); - expect(ops.vars).toEqual([0,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(4); - }); - - it("Checking step left with 4 bits per var", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); - }); - expect(ops1.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v1=stepLeft(); - expect(ops1.vars).toEqual([0,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - expect(org.x).toBe(2); - expect(org.y).toBe(4); - - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }); - }); - xdescribe('onMyX() method', () => { let org; let ops; diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 2600d66..a4ea156 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -10,6 +10,7 @@ const QUIET_ALL = 0; const QUIET_IMPORTANT = 1; const QUIET_NO = 2; +const ENERGY_COLOR = 10000; const IS_NODE_JS = typeof window === 'undefined'; class ClientConfig extends Config {} @@ -58,6 +59,15 @@ ClientConfig.init({ * {Number} World height */ worldHeight: 1080 * 4, + /** + * {Number} Color index of one energy dot + */ + worldEnergyColor: ENERGY_COLOR, + /** + * {Number} Amount of all energy in a world including organisms and all kinds + * of energy. Total energy should not be greater then this value. + */ + worldEnergy: 0x6d3b4 * 10000, // Helper.getColor(ENERGY_COLOR) === 0x6d3b4 /** * {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 diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 1d49614..5625b86 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -70,7 +70,8 @@ class Operators { MAX_BITS - (bitsPerOp), // return MAX_BITS - (bitsPerOp), // bracket MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2), // toMem - MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2) // fromMem + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2), // fromMem + MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 2) // rand ]; /** * {Object} Map for all available operator handlers diff --git a/tests/jasmine.json b/tests/jasmine.json index 0b4a9cd..551a712 100644 --- a/tests/jasmine.json +++ b/tests/jasmine.json @@ -4,8 +4,9 @@ "1client/src/**/*[sS]pec.js", "1common/src/**/*[sS]pec.js", "1server/src/**/*[sS]pec.js", - "common/src/FastArraySpec.js", - "client/src/vm/OperatorsSpec.js" + "1common/src/FastArraySpec.js", + "1client/src/vm/OperatorsSpec.js", + "client/src/manager/plugins/organisms/dos/OperatorsSpec.js" ], "stopSpecOnExpectationFailure": false, "random": false From 952e87ec92a4937cb470eba9ad7d167d4c70e637 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 7 Jun 2018 07:23:12 +0300 Subject: [PATCH 54/88] Updated default config --- client/src/manager/plugins/objects/Config.js | 2 +- client/src/manager/plugins/organisms/Config.js | 6 +++--- client/src/share/Config.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/manager/plugins/objects/Config.js b/client/src/manager/plugins/objects/Config.js index e18d12d..0812cb9 100644 --- a/client/src/manager/plugins/objects/Config.js +++ b/client/src/manager/plugins/objects/Config.js @@ -30,7 +30,7 @@ const Config = { * example all the screen will be filled by objects. As many values by four, you set as * many places with objects will be created. In case of null, grouping will be disabled. */ - groups: [1920 * 2, 1080 * 2, 50, 50] + groups: [1920 * 2, 1080 * 2, 300, 300] }; module.exports = Config; \ No newline at end of file diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 3145d1f..15ca770 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -68,7 +68,7 @@ const Config = { /** * {Number} Minimum energy for cloning */ - orgCloneMinEnergy: .8 * ENERGY_VALUE, + orgCloneMinEnergy: 8 * ENERGY_VALUE, /** * {Boolean} If true, then random organism will be killed after new one has * cloned and amount of organisms is greater then orgMaxOrgs config. false @@ -116,13 +116,13 @@ const Config = { /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: ENERGY_VALUE, + orgMaxEnergy: 10 * ENERGY_VALUE, /** * {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: ENERGY_VALUE, + orgStartEnergy: 10 * ENERGY_VALUE, /** * {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 a4ea156..c00a417 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -67,7 +67,7 @@ ClientConfig.init({ * {Number} Amount of all energy in a world including organisms and all kinds * of energy. Total energy should not be greater then this value. */ - worldEnergy: 0x6d3b4 * 10000, // Helper.getColor(ENERGY_COLOR) === 0x6d3b4 + worldEnergy: 0x6d3b4 * 10000 * 10, // Helper.getColor(ENERGY_COLOR) === 0x6d3b4 /** * {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 c057cf1a6beda3519ba8cf6fa6e13d55668c4edd Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 8 Jun 2018 23:34:33 +0300 Subject: [PATCH 55/88] added test for OperatorsDos |#145 --- .../plugins/organisms/dos/OperatorsSpec.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 8e38dc4..57c6d0b 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -5,12 +5,15 @@ const Config = require('./../../../../share/Config').Config; const Helper = require('./../../../../../../common/src/Helper'); const OrganismDos = require('./Organism'); const World = require('./../../../../view/World').World; +const EVENTS = require('./../../../../share/Events').EVENTS; +const DIRS = require('./../../../../../../common/src/Directions').DIR; describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { const hex = Helper.toHexNum; const ww = Config.worldWidth; const wh = Config.worldHeight; const oldMan = global.man; + let org; let cbpv; let ccb; let ops; @@ -51,11 +54,13 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world = new World(w, h); vars = [0,1,2,3]; offs = new Array(10); - ops = new OperatorsDos(offs, vars); + org = new OrganismDos(0, 0, 0, {}); + ops = new OperatorsDos(offs, vars, org); }); afterEach (() => { ops.destroy(); global.man.world.destroy(); + org.destroy(); ops = null; offs = null; vars = null; @@ -190,10 +195,11 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { describe('onStepLeft() method', () => { it("Checking step left", () => { - ops.vars[3] = 11; - ops. - expect(ops.operators[hex('101101')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,0,2,11]); + org.dir = DIRS.LEFT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === 0 && x1 === -1 && y1 === 0).toBe(true); + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); }); xit("Checking step left with no free space on the left", () => { From ec41e050d2ef9ac7df3b317096e0ab23aaad824e Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 15 Jun 2018 23:23:19 +0300 Subject: [PATCH 56/88] added tests for lookAt and step operators #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 122 ++++++++++++------ 1 file changed, 79 insertions(+), 43 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 57c6d0b..440fd96 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -68,32 +68,32 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { Config.worldHeight = wh; }); - describe('onLookAt() method', () => { - it("Checking onLookAt() is found nothing", () => { + describe('lookAt() method', () => { + it("Checking lookAt() is found nothing", () => { expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,0,2,3]); }); - it("Checking onLookAt() looking outside of the world - x", () => { + it("Checking lookAt() looking outside of the world - x", () => { ops.vars[0] = 11; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([11,0,2,3]); }); - it("Checking onLookAt() looking outside of the world - y", () => { + it("Checking lookAt() looking outside of the world - y", () => { ops.vars[3] = 11; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,0,2,11]); }); - it('Checking onLookAt() found an energy', () => { + it('Checking lookAt() found an energy', () => { global.man.world.setDot(0,3,0xaabbcc); expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,1,2,3]); global.man.world.setDot(0,3,0); }); - it('Checking onLookAt() found an object', () => { + it('Checking lookAt() found an object', () => { global.man.world.setDot(0,3,0xaabbcc); global.man.positions[0][3] = -2; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); @@ -102,7 +102,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[0][3] = 0; }); - it('Checking onLookAt() found an organism', () => { + it('Checking lookAt() found an organism', () => { global.man.world.setDot(0,3,0xaabbcc); global.man.positions[0][3] = {energy: 123}; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); @@ -111,14 +111,14 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[0][3] = 0; }); - it('Checking onLookAt() with floating coordinates', () => { + it('Checking lookAt() with floating coordinates', () => { ops.vars[0] = .1; ops.vars[3] = .2; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([.1,0,2,.2]); }); - describe('onLookAt() method 3bits per var', () => { + describe('lookAt() method 3bits per var', () => { let bpv; let ops; let vars; @@ -142,31 +142,31 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { OConfig.codeBitsPerVar = bpv; }); - it("Checking onLookAt() is found nothing", () => { + it("Checking lookAt() is found nothing", () => { expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,0,2,3,4,5,6,7]); }); - it("Checking onLookAt() looking outside of the world - x", () => { + it("Checking lookAt() looking outside of the world - x", () => { ops.vars[0] = 11; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([11,0,2,3,4,5,6,7]); }); - it("Checking onLookAt() looking outside of the world - y", () => { + it("Checking lookAt() looking outside of the world - y", () => { ops.vars[3] = 11; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,0,2,11,4,5,6,7]); }); - it('Checking onLookAt() found an energy', () => { + it('Checking lookAt() found an energy', () => { global.man.world.setDot(0,3,0xaabbcc); expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); global.man.world.setDot(0,3,0); }); - it('Checking onLookAt() found an object', () => { + it('Checking lookAt() found an object', () => { global.man.world.setDot(0,3,0xaabbcc); global.man.positions[0][3] = -2; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); @@ -175,7 +175,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[0][3] = 0; }); - it('Checking onLookAt() found an organism', () => { + it('Checking lookAt() found an organism', () => { global.man.world.setDot(0,3,0xaabbcc); global.man.positions[0][3] = {energy: 123}; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); @@ -184,7 +184,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[0][3] = 0; }); - it('Checking onLookAt() with floating coordinates', () => { + it('Checking lookAt() with floating coordinates', () => { ops.vars[0] = .1; ops.vars[3] = .2; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); @@ -193,46 +193,82 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); - describe('onStepLeft() method', () => { + describe('step() method', () => { it("Checking step left", () => { + org.x = 1; + org.y = 1; org.dir = DIRS.LEFT; org.on(EVENTS.STEP, (o,x,y,x1,y1) => { - expect(x === 0 && y === 0 && x1 === -1 && y1 === 0).toBe(true); + expect(x === 1 && y === 1 && x1 === 0 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; }); expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(1); }); - xit("Checking step left with no free space on the left", () => { - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); + it("Checking step left with no free space on the left", () => { + org.dir = DIRS.LEFT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === 0 && x1 === -1 && y1 === 0).toBe(true); + o.x = x; + o.y = y1; }); - expect(ops.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v0=stepLeft(); - expect(ops.vars).toEqual([0,1,2,3]); - expect(org.x).toBe(3); - expect(org.y).toBe(4); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(0); }); - xit("Checking step left with 4 bits per var", () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); + describe('step() method with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll (() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll (() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0,1,2,3,4,5,6,7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach (() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); - org.x = 3; - org.y = 4; - org.on(EVENTS.STEP, (org, x1, y1, x2, y2) => { - org.x = x2; - org.y = y2; - expect(x1 === 3 && y1 === 4 && x2 === 2 && y2 === 4).toBe(true); + it("Checking step left", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 0 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(1); }); - expect(ops1.onStepLeft(0x0a1fffff, 0, org)).toEqual(1); // v1=stepLeft(); - expect(ops1.vars).toEqual([0,2,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - expect(org.x).toBe(2); - expect(org.y).toBe(4); - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); + it("Checking step left with no space", () => { + org.dir = DIRS.LEFT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === 0 && x1 === -1 && y1 === 0).toBe(true); + o.x = x; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(0); + }); }); }); From 94324bc13294e54a64461f1ce8f121d370253c6d Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 16 Jun 2018 18:40:19 +0300 Subject: [PATCH 57/88] added tests for dir, myX, myY, and eat operators #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 470 ++++++++++++++---- 1 file changed, 372 insertions(+), 98 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 440fd96..4fa6c36 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -68,7 +68,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { Config.worldHeight = wh; }); - describe('lookAt() method', () => { + describe('lookAt() operator', () => { it("Checking lookAt() is found nothing", () => { expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); expect(ops.vars).toEqual([0,0,2,3]); @@ -193,7 +193,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); - describe('step() method', () => { + describe('step() operator', () => { it("Checking step left", () => { org.x = 1; org.y = 1; @@ -220,7 +220,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.y).toBe(0); }); - describe('step() method with 3bits per var', () => { + describe('step() operator with 3bits per var', () => { let bpv; let ops; let vars; @@ -272,143 +272,417 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); - xdescribe('onEatLeft() method', () => { - let org; - let ops; - const w = Config.worldWidth; - const h = Config.worldHeight; + describe('dir() operator', () => { + it("Checking up direction 1", () => { + ops.vars[0] = DIRS.UP; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.UP); + }); + it("Checking up direction 2", () => { + ops.vars[0] = DIRS.UP + 4; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.UP); + }); + it("Checking up direction 3", () => { + ops.vars[0] = DIRS.UP + 4 + .1; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.UP); + }); - beforeEach(() => {Config.worldHeight = Config.worldWidth = 10;org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([1], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy(); Config.worldHeight = h; Config.worldWidth = w}); + it("Checking right direction 1", () => { + ops.vars[0] = DIRS.RIGHT; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.RIGHT); + }); + it("Checking right direction 2", () => { + ops.vars[0] = DIRS.RIGHT + 4; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.RIGHT); + }); + it("Checking right direction 3", () => { + ops.vars[0] = DIRS.RIGHT + 4 + .1; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.RIGHT); + }); - it("Checking eating nothing", () => { - ops.vars = [1, 0, 1, 2]; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([0, 0, 1, 2]); + it("Checking down direction 1", () => { + ops.vars[0] = DIRS.DOWN; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.DOWN); }); - it("Checking eating nothing 2", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 0; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([0,1,2,3]); + it("Checking down direction 2", () => { + ops.vars[0] = DIRS.DOWN + 4; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.DOWN); + }); + it("Checking down direction 3", () => { + ops.vars[0] = DIRS.DOWN + 4 + .1; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.DOWN); }); - it("Checking eating energy", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 5; + it("Checking left direction 1", () => { + ops.vars[0] = DIRS.LEFT; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.LEFT); + }); + it("Checking left direction 2", () => { + ops.vars[0] = DIRS.LEFT + 4; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.LEFT); + }); + it("Checking left direction 3", () => { + ops.vars[0] = DIRS.LEFT + 4 + .1; + expect(ops.operators[hex('101110 00')].call(ops, 0, hex('101110 00'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.LEFT); + }); + + it("Checking left direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 0 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; }); - org.x = 2; - org.y = 3; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([5,1,2,3]); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(1); + }); + it("Checking right direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 2 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(2); + expect(org.y).toBe(1); + }); + it("Checking up direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 0).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(0); + }); + it("Checking down direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 2).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(2); }); - it('Checking eating with 3bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); + describe('dir() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(4); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 5; + it("Checking up direction 1", () => { + ops.vars[0] = DIRS.UP; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.UP); + }); + it("Checking up direction 2", () => { + ops.vars[0] = DIRS.UP + 4; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.UP); + }); + it("Checking up direction 3", () => { + ops.vars[0] = DIRS.UP + 4 + .1; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.UP); }); - org.x = 2; - org.y = 3; - expect(ops1.onEatLeft(0x0633ffff, 0, org)).toEqual(1); // v1=eatLeft(v4); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }) - }); + it("Checking right direction 1", () => { + ops.vars[0] = DIRS.RIGHT; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.RIGHT); + }); + it("Checking right direction 2", () => { + ops.vars[0] = DIRS.RIGHT + 4; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.RIGHT); + }); + it("Checking right direction 3", () => { + ops.vars[0] = DIRS.RIGHT + 4 + .1; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.RIGHT); + }); - xdescribe('onMyX() method', () => { - let org; - let ops; + it("Checking down direction 1", () => { + ops.vars[0] = DIRS.DOWN; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.DOWN); + }); + it("Checking down direction 2", () => { + ops.vars[0] = DIRS.DOWN + 4; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.DOWN); + }); + it("Checking down direction 3", () => { + ops.vars[0] = DIRS.DOWN + 4 + .1; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.DOWN); + }); - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); + it("Checking left direction 1", () => { + ops.vars[0] = DIRS.LEFT; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.LEFT); + }); + it("Checking left direction 2", () => { + ops.vars[0] = DIRS.LEFT + 4; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.LEFT); + }); + it("Checking left direction 3", () => { + ops.vars[0] = DIRS.LEFT + 4 + .1; + expect(ops.operators[hex('101110 000')].call(ops, 0, hex('101110 000'), org)).toEqual(1); + expect(org.dir).toBe(DIRS.LEFT); + }); + + it("Checking left direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 0 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(1); + }); + it("Checking right direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 2 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(2); + expect(org.y).toBe(1); + }); + it("Checking up direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 0).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(0); + }); + it("Checking down direction while moving", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + org.on(EVENTS.STEP, (o, x, y, x1, y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 2).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(2); + }); + }); + }); + describe('myX() method', () => { it("Checking simple values", () => { org.x = 1; - expect(ops.onMyX(0x0c1fffff, 0, org)).toEqual(1); // v0=myX() + expect(ops.operators[hex('101111 00')].call(ops, 0, hex('101111 00'), org)).toEqual(1); // v0=myX() expect(ops.vars).toEqual([1,1,2,3]); org.x = 3; - expect(ops.onMyX(0x0c6fffff, 0, org)).toEqual(1); // v1=myX() + expect(ops.operators[hex('101111 01')].call(ops, 0, hex('101111 01'), org)).toEqual(1); // v1=myX() expect(ops.vars).toEqual([1,3,2,3]); org.x = 0; - expect(ops.onMyX(0x0cffffff, 0, org)).toEqual(1); // v3=myX() + expect(ops.operators[hex('101111 11')].call(ops, 0, hex('101111 11'), org)).toEqual(1); // v3=myX() expect(ops.vars).toEqual([1,3,2,0]); }); - it('Checking simple values with 4 bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); - - org.x = 3; - expect(ops1.onMyX(0x0c1fffff, 0, org)).toEqual(1); // v1=myX() - expect(ops1.vars).toEqual([0,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); - org.x = 3; - expect(ops1.onMyX(0x0c6fffff, 0, org)).toEqual(1); // v6=myX() - expect(ops1.vars).toEqual([0,3,2,3,4,5,3,7,8,9,10,11,12,13,14,15]); - org.x = 0; - expect(ops1.onMyX(0x0cffffff, 0, org)).toEqual(1); // v15=myX() - expect(ops1.vars).toEqual([0,3,2,3,4,5,3,7,8,9,10,11,12,13,14,0]); + describe('myX() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); + it("Checking simple values", () => { + org.x = 1; + expect(ops.operators[hex('101111 000')].call(ops, 0, hex('101111 000'), org)).toEqual(1); // v0=myX() + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + org.x = 3; + expect(ops.operators[hex('101111 001')].call(ops, 0, hex('101111 001'), org)).toEqual(1); // v1=myX() + expect(ops.vars).toEqual([1,3,2,3,4,5,6,7]); + org.x = 0; + expect(ops.operators[hex('101111 011')].call(ops, 0, hex('101111 011'), org)).toEqual(1); // v3=myX() + expect(ops.vars).toEqual([1,3,2,0,4,5,6,7]); + }); }); }); - xdescribe('onMyY() method', () => { - let org; - let ops; - - beforeEach(() => {org = new OrganismDos('0', 0, 0, {}); ops = new OperatorsDos([], [0, 1, 2, 3], org)}); - afterEach (() => {ops.destroy(); org.destroy()}); - + describe('myY() method', () => { it("Checking simple values", () => { org.y = 1; - expect(ops.onMyY(0x0c1fffff, 0, org)).toEqual(1); // v0=myY() + expect(ops.operators[hex('110000 00')].call(ops, 0, hex('110000 00'), org)).toEqual(1); // v0=myY() expect(ops.vars).toEqual([1,1,2,3]); org.y = 3; - expect(ops.onMyY(0x0c6fffff, 0, org)).toEqual(1); // v1=myY() + expect(ops.operators[hex('110000 01')].call(ops, 0, hex('110000 01'), org)).toEqual(1); // v1=myY() expect(ops.vars).toEqual([1,3,2,3]); org.y = 0; - expect(ops.onMyY(0x0cffffff, 0, org)).toEqual(1); // v3=myY() + expect(ops.operators[hex('110000 11')].call(ops, 0, hex('110000 11'), org)).toEqual(1); // v3=myY() expect(ops.vars).toEqual([1,3,2,0]); }); - it('Checking simple values with 4 bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 4; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], org); + describe('myY() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking simple values", () => { + org.y = 1; + expect(ops.operators[hex('110000 000')].call(ops, 0, hex('110000 000'), org)).toEqual(1); // v0=myY() + expect(ops.vars).toEqual([1,1,2,3,4,5,6,7]); + org.y = 3; + expect(ops.operators[hex('110000 001')].call(ops, 0, hex('110000 001'), org)).toEqual(1); // v1=myY() + expect(ops.vars).toEqual([1,3,2,3,4,5,6,7]); + org.y = 0; + expect(ops.operators[hex('110000 011')].call(ops, 0, hex('110000 011'), org)).toEqual(1); // v3=myY() + expect(ops.vars).toEqual([1,3,2,0,4,5,6,7]); + }); + }); + }); + describe('eat() operator', () => { + it("Checking eating nothing", () => { + const energy = org.energy; + ops.vars = [0, 0, 1, 2]; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 0, 1, 2]); + expect(org.energy).toEqual(energy); + }); + it("Checking eating nothing 2", () => { + const energy = org.energy; + ops.vars = [1, 0, 1, 2]; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2]); + expect(org.energy).toEqual(energy); + }); + + xit("Checking eating energy", () => { + org.on(EVENTS.EAT, (org, x, y, ret) => { + expect(ret.ret).toBe(1); + expect(x).toBe(1); + expect(y).toBe(3); + ret.ret = 5; + }); + org.x = 2; org.y = 3; - expect(ops1.onMyY(0x0c1fffff, 0, org)).toEqual(1); // v1=myX() - expect(ops1.vars).toEqual([0,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15]); + expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); + expect(ops.vars).toEqual([5,1,2,3]); + }); + + xit('Checking eating with 3bits per var', () => { + let bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); + + org.on(EVENTS.EAT, (org, x, y, ret) => { + expect(ret.ret).toBe(4); + expect(x).toBe(1); + expect(y).toBe(3); + ret.ret = 5; + }); + org.x = 2; org.y = 3; - expect(ops1.onMyY(0x0c6fffff, 0, org)).toEqual(1); // v6=myX() - expect(ops1.vars).toEqual([0,3,2,3,4,5,3,7,8,9,10,11,12,13,14,15]); - org.y = 0; - expect(ops1.onMyY(0x0cffffff, 0, org)).toEqual(1); // v15=myX() - expect(ops1.vars).toEqual([0,3,2,3,4,5,3,7,8,9,10,11,12,13,14,0]); + expect(ops1.onEatLeft(0x0633ffff, 0, org)).toEqual(1); // v1=eatLeft(v4); + expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); OConfig.codeBitsPerVar = bpv; ops1.destroy(); - }); + }) }); xdescribe('onCheckLeft() method', () => { From 263a9ddb6c3f7d74b36ac2214c36db59a4772e81 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 18 Jun 2018 22:39:39 +0300 Subject: [PATCH 58/88] added tests for eat operator #145 --- .../plugins/organisms/dos/Operators.js | 22 ++++-- .../plugins/organisms/dos/OperatorsSpec.js | 78 ++++++++++++------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index e03f4fe..c5e98c3 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -570,6 +570,20 @@ class OperatorsDos extends Operators { */ get length() {return OperatorsDos.OPERATOR_AMOUNT} + /** + * Returns World instance reference + * @returns {World} + */ + get world() {return this._world} + + destroy() { + super.destroy(); + + this._world = null; + this._positions = null; + this._obs = null; + } + /** * Returns type of the dot under x,y coordinates * @param {Number} x X coordinate @@ -586,14 +600,6 @@ class OperatorsDos extends Operators { return ORGANISM; } - - destroy() { - super.destroy(); - - this._world = null; - this._positions = null; - this._obs = null; - } } OperatorsDos.compile(); diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 4fa6c36..d0aa79a 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -7,6 +7,7 @@ const OrganismDos = require('./Organism'); const World = require('./../../../../view/World').World; const EVENTS = require('./../../../../share/Events').EVENTS; const DIRS = require('./../../../../../../common/src/Directions').DIR; +const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { const hex = Helper.toHexNum; @@ -636,7 +637,11 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); describe('eat() operator', () => { - it("Checking eating nothing", () => { + let maxEnergy = OConfig.orgMaxEnergy; + beforeEach(() => OConfig.orgMaxEnergy = 100); + afterEach (() => OConfig.orgMaxEnergy = maxEnergy); + + it("Checking eating nothing 1", () => { const energy = org.energy; ops.vars = [0, 0, 1, 2]; expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); @@ -651,38 +656,53 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.energy).toEqual(energy); }); - xit("Checking eating energy", () => { - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(1); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops.onEatLeft(0x061fffff, 0, org)).toEqual(1); // v0=eatLeft(v1); - expect(ops.vars).toEqual([5,1,2,3]); + it("Checking eating energy", () => { + org.energy = 1; + ops.vars = [1, 0, 1, 2]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2]); + expect(org.energy).toEqual(2); }); - xit('Checking eating with 3bits per var', () => { - let bpv = OConfig.codeBitsPerVar; - OConfig.codeBitsPerVar = 3; - let ops1 = new OperatorsDos([1], [0,1,2,3,4,5,6,7], org); + it("Checking eating world object", () => { + org.energy = 1; + ops.vars = [1, 0, 1, 2]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY2; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2]); + expect(org.energy).toEqual(1); - org.on(EVENTS.EAT, (org, x, y, ret) => { - expect(ret.ret).toBe(4); - expect(x).toBe(1); - expect(y).toBe(3); - ret.ret = 5; - }); - org.x = 2; - org.y = 3; - expect(ops1.onEatLeft(0x0633ffff, 0, org)).toEqual(1); // v1=eatLeft(v4); - expect(ops1.vars).toEqual([0,5,2,3,4,5,6,7]); + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); - OConfig.codeBitsPerVar = bpv; - ops1.destroy(); - }) + it("Checking eating other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + const energy = org2.energy; + org.energy = 1; + ops.vars = [1, 0, 1, 2]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2]); + expect(org.energy).toEqual(2); + expect(org2.energy).toEqual(energy - 1); + + + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); }); xdescribe('onCheckLeft() method', () => { From d5fbfed4f8c3e157fefaa6650ea20b67f466f86e Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 18 Jun 2018 22:57:47 +0300 Subject: [PATCH 59/88] added test for OperatorsDos |#145 --- .../plugins/organisms/dos/OperatorsSpec.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index d0aa79a..cc5521e 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -700,6 +700,26 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org2.energy).toEqual(energy - 1); + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); + + it("Checking killing other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + org2.energy = 1; + org.energy = 1; + ops.vars = [1, 0, 1, 2]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2]); + expect(org.energy).toEqual(2); + expect(org2.energy).toEqual(0); + expect(org2.vm).toEqual(null); + global.man.positions[1][0] = 0; ops.world.setDot(1,0,0); }); From 1dec3b63fdeda67f60b523b5c200164a074a91da Mon Sep 17 00:00:00 2001 From: tmptrash Date: Tue, 19 Jun 2018 15:41:33 +0300 Subject: [PATCH 60/88] added tests for eat operator #145 --- .../plugins/organisms/dos/Operators.js | 1 - .../plugins/organisms/dos/OperatorsSpec.js | 117 ++++++++++++++++++ package.json | 10 +- 3 files changed, 122 insertions(+), 6 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index c5e98c3..f76fae1 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -291,7 +291,6 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function put(line, num, org) { - return ++line; let put = this.vars[${v0}]; if (put <= 0) {return ++line} if (put > 0xffffff) {put = 0xffffff} diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index d0aa79a..ae62407 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -703,6 +703,123 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[1][0] = 0; ops.world.setDot(1,0,0); }); + + describe('eat() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking eating nothing 1", () => { + const energy = org.energy; + ops.vars = [0, 0, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 0, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(energy); + }); + it("Checking eating nothing 2", () => { + const energy = org.energy; + ops.vars = [1, 0, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(energy); + }); + it("Checking eating energy", () => { + org.energy = 1; + ops.vars = [1, 0, 1, 2, 3, 4, 5, 6, 7]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(2); + }); + + it("Checking eating world object", () => { + org.energy = 1; + ops.vars = [1, 0, 1, 2, 3, 4, 5, 6, 7]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY2; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(1); + + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); + + it("Checking eating other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + const energy = org2.energy; + org.energy = 1; + ops.vars = [1, 0, 1, 2, 3, 4, 5, 6, 7]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(2); + expect(org2.energy).toEqual(energy - 1); + + + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); + }); + }); + + describe('put() operator', () => { + it("Checking put nothing", () => { + const energy = org.energy; + ops.vars = [0, 1, 2, 3]; + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(org.energy).toEqual(energy); + }); + + it("Checking put of energy", () => { + const energy = org.energy = 10; + org.x = 1; + org.y = 1; + ops.vars = [1, 1, 2, 3]; + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3]); + expect(org.energy).toEqual(energy - 1); + }); + + it("Checking killing of organism while put energy", () => { + org.energy = 1; + org.x = 1; + org.y = 1; + ops.vars = [1, 1, 2, 3]; + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3]); + expect(org.energy).toEqual(0); + }); }); xdescribe('onCheckLeft() method', () => { diff --git a/package.json b/package.json index 5c98a7e..5631b07 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,11 @@ }, "dependencies": { "babel-cli": "^6.24.1", - "babel-preset-env": "^1.6.0", - "jasmine": "^2.6.0", + "babel-preset-env": "^1.7.0", + "jasmine": "^2.99.0", "js-beautify": "^1.6.14", - "panzoom": "^4.1.0", - "webpack": "^3.9.1", + "panzoom": "^4.5.0", + "webpack": "^3.12.0", "ws": "^3.3.2" }, "scripts": { @@ -41,7 +41,7 @@ "homepage": "https://github.com/tmptrash/jevo.js#readme", "devDependencies": { "babel-register": "latest", - "clean-webpack-plugin": "^0.1.17", + "clean-webpack-plugin": "^0.1.19", "ignore-loader": "^0.1.2" } } From 84d7423e852a6a6bd81f7505b8f1f182de3300ef Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 19 Jun 2018 18:55:53 +0300 Subject: [PATCH 61/88] small fix --- client/src/manager/plugins/organisms/dos/Operators.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index c5e98c3..668a610 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -295,8 +295,8 @@ class OperatorsDos extends Operators { let put = this.vars[${v0}]; if (put <= 0) {return ++line} if (put > 0xffffff) {put = 0xffffff} - let x = org.dirX; - let y = org.dirY; + const x = org.dirX; + const y = org.dirY; if (!IN_WORLD(x, y)) {return ++line} if (this._world.data[x][y] !== 0) {return ++line} if (org.energy <= put) { From 3b7c0a7fbcb30c4656b83ecba852a47f74340492 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 19 Jun 2018 23:45:51 +0300 Subject: [PATCH 62/88] added test for put operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 153 +++++++++++++++++- 1 file changed, 149 insertions(+), 4 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index ae62407..333957d 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -96,9 +96,9 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { it('Checking lookAt() found an object', () => { global.man.world.setDot(0,3,0xaabbcc); - global.man.positions[0][3] = -2; + global.man.positions[0][3] = OBJECT_TYPES.TYPE_ENERGY2; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,-2,2,3]); + expect(ops.vars).toEqual([0,OBJECT_TYPES.TYPE_ENERGY2,2,3]); global.man.world.setDot(0,3,0); global.man.positions[0][3] = 0; }); @@ -169,9 +169,9 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { it('Checking lookAt() found an object', () => { global.man.world.setDot(0,3,0xaabbcc); - global.man.positions[0][3] = -2; + global.man.positions[0][3] = OBJECT_TYPES.TYPE_ENERGY2; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,-2,2,3,4,5,6,7]); + expect(ops.vars).toEqual([0,OBJECT_TYPES.TYPE_ENERGY2,2,3,4,5,6,7]); global.man.world.setDot(0,3,0); global.man.positions[0][3] = 0; }); @@ -811,6 +811,16 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.energy).toEqual(energy - 1); }); + it("Checking put huge amount of energy", () => { + org.energy = 0xfffffff; + org.x = 1; + org.y = 1; + ops.vars = [0xfffffff, 1, 2, 3]; + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([0xfffffff, 1, 2, 3]); + expect(org.energy).toEqual(0xfffffff - 0xffffff); + }); + it("Checking killing of organism while put energy", () => { org.energy = 1; org.x = 1; @@ -820,6 +830,141 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([1, 1, 2, 3]); expect(org.energy).toEqual(0); }); + + it("Checking put if organism is out of bounds", () => { + org.energy = 1; + org.x = 0; + org.y = 0; + org.dir = DIRS.UP; + ops.vars = [1, 1, 2, 3]; + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3]); + expect(org.energy).toEqual(1); + }); + + it("Checking negative put", () => { + org.energy = 1; + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + ops.vars = [-1, 1, 2, 3]; + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([-1, 1, 2, 3]); + expect(org.energy).toEqual(1); + }); + + it("Checking put if something is there", () => { + org.energy = 1; + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + ops.vars = [1, 1, 2, 3]; + global.man.world.setDot(1,0,0xaabbcc); + expect(ops.operators[hex('110010 00')].call(ops, 0, hex('110010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3]); + expect(org.energy).toEqual(1); + + global.man.world.setDot(1,0,0); + }); + + describe('eat() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking put nothing", () => { + const energy = org.energy; + ops.vars = [0, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(energy); + }); + + it("Checking put of energy", () => { + const energy = org.energy = 10; + org.x = 1; + org.y = 1; + ops.vars = [1, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(energy - 1); + }); + + it("Checking put huge amount of energy", () => { + org.energy = 0xfffffff; + org.x = 1; + org.y = 1; + ops.vars = [0xfffffff, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([0xfffffff, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(0xfffffff - 0xffffff); + }); + + it("Checking killing of organism while put energy", () => { + org.energy = 1; + org.x = 1; + org.y = 1; + ops.vars = [1, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(0); + }); + + it("Checking put if organism is out of bounds", () => { + org.energy = 1; + org.x = 0; + org.y = 0; + org.dir = DIRS.UP; + ops.vars = [1, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(1); + }); + + it("Checking negative put", () => { + org.energy = 1; + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + ops.vars = [-1, 1, 2, 3, 4, 5, 6, 7]; + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([-1, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(1); + }); + + it("Checking put if something is there", () => { + org.energy = 1; + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + ops.vars = [1, 1, 2, 3, 4, 5, 6, 7]; + global.man.world.setDot(1,0,0xaabbcc); + expect(ops.operators[hex('110010 000')].call(ops, 0, hex('110010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 1, 2, 3, 4, 5, 6, 7]); + expect(org.energy).toEqual(1); + + global.man.world.setDot(1,0,0); + }); + }); }); xdescribe('onCheckLeft() method', () => { From c89b2042315cbd9b8c24be638f064b35c912b008 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 19 Jun 2018 23:52:36 +0300 Subject: [PATCH 63/88] added test for eat operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 333957d..b8a8ffe 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -684,6 +684,17 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { ops.world.setDot(1,0,0); }); + it("Checking eating out of the world", () => { + org.energy = 1; + ops.vars = [1, 0, 1, 2]; + org.dir = DIRS.UP; + org.x = 0; + org.y = 0; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2]); + expect(org.energy).toEqual(1); + }); + it("Checking eating other organism", () => { const org2 = new OrganismDos(1, 0, 0, {}); const energy = org2.energy; @@ -770,6 +781,17 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { ops.world.setDot(1,0,0); }); + it("Checking eating out of the world", () => { + org.energy = 1; + ops.vars = [1, 0, 1, 2, 3, 4, 5, 6]; + org.dir = DIRS.UP; + org.x = 0; + org.y = 0; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6]); + expect(org.energy).toEqual(1); + }); + it("Checking eating other organism", () => { const org2 = new OrganismDos(1, 0, 0, {}); const energy = org2.energy; From d8ac97fcd670f41c91c3ff879ed7f20e9da23a80 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 21 Jun 2018 20:51:06 +0300 Subject: [PATCH 64/88] added test for lookAt, step operators #145 added new config OConfig.orgSizeAffectsEnergy typeof x === 'undefined' -> x === undefined optimizations --- .../src/manager/plugins/organisms/Config.js | 7 +- .../plugins/organisms/dos/Operators.js | 8 +- .../plugins/organisms/dos/OperatorsSpec.js | 227 ++++++++++++++++-- .../manager/plugins/status/charts/Charts.js | 12 +- client/src/share/Config.js | 3 + client/src/vm/Code2JS.js | 2 +- client/src/vm/Operators.js | 4 +- client/src/vm/VM.js | 3 +- common/src/Configurable.js | 4 +- common/src/Helper.js | 4 +- common/src/Observer.js | 2 +- common/src/plugins/Request.js | 2 +- 12 files changed, 240 insertions(+), 38 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index 15ca770..a39ff4d 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -160,6 +160,11 @@ const Config = { * whole world. */ orgPosition: [1920 + 1920/1.5, 1080 * 2, 500, 500, 1920 * 3 - 1920/1.5, 1080 * 2, 500, 500], + /** + * {Boolean} true means, that code size affects amount of grabbed energy from + * organism by the system on every code line run + */ + orgSizeAffectsEnergy: false, /** * {Number} If organism reach this limit of amount of vm lines, then codeSizeCoef * will be used during it's energy grabbing by system. We use this approach, @@ -167,7 +172,7 @@ const Config = { * it's possible for organisms to go outside the limit by inventing new * effective mechanisms of energy obtaining. */ - codeMaxSize: 300, + codeMaxSize: 100, /** * {Number} Amount of bits for storing a numeric constant inside byte code */ diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 4fb6ca0..0da2a3e 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -25,7 +25,6 @@ const NORMALIZE_NO_DIR = Helper.normalizeNoDir; 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() @@ -102,7 +101,7 @@ class OperatorsDos extends Operators { const x = (vars[${v1}] + .5) << 0; const y = (vars[${v2}] + .5) << 0; if (!IN_WORLD(x, y)) { - vars[${v0}] = 0; + vars[${v0}] = ${EMPTY}; return ++line; } vars[${v0}] = this._getDotType(x, y); @@ -492,7 +491,10 @@ class OperatorsDos extends Operators { eval(`Operators.global.fn = function check(line, num, org) { const x = org.dirX; const y = org.dirY; - if (!IN_WORLD(x, y)) {return ++line} + if (!IN_WORLD(x, y)) { + this.vars[${v0}] = ${EMPTY}; + return ++line; + } this.vars[${v0}] = this._getDotType(x, y); return ++line; diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index b8a8ffe..862954a 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -9,6 +9,10 @@ const EVENTS = require('./../../../../share/Events').EVENTS; const DIRS = require('./../../../../../../common/src/Directions').DIR; const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; +const EMPTY = 0; +const ENERGY = 1; +const ORGANISM = 2; + describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { const hex = Helper.toHexNum; const ww = Config.worldWidth; @@ -72,25 +76,25 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { describe('lookAt() operator', () => { it("Checking lookAt() is found nothing", () => { expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,0,2,3]); + expect(ops.vars).toEqual([0,EMPTY,2,3]); }); it("Checking lookAt() looking outside of the world - x", () => { - ops.vars[0] = 11; + ops.vars[0] = w + 1; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([11,0,2,3]); + expect(ops.vars).toEqual([w + 1,EMPTY,2,3]); }); it("Checking lookAt() looking outside of the world - y", () => { - ops.vars[3] = 11; + ops.vars[3] = h + 1; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,0,2,11]); + expect(ops.vars).toEqual([0,EMPTY,2,h + 1]); }); it('Checking lookAt() found an energy', () => { global.man.world.setDot(0,3,0xaabbcc); expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,1,2,3]); + expect(ops.vars).toEqual([0,ENERGY,2,3]); global.man.world.setDot(0,3,0); }); @@ -107,7 +111,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(0,3,0xaabbcc); global.man.positions[0][3] = {energy: 123}; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,2,2,3]); + expect(ops.vars).toEqual([0,ORGANISM,2,3]); global.man.world.setDot(0,3,0); global.man.positions[0][3] = 0; }); @@ -116,7 +120,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { ops.vars[0] = .1; ops.vars[3] = .2; expect(ops.operators[hex('101100 01 00 11')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([.1,0,2,.2]); + expect(ops.vars).toEqual([.1,EMPTY,2,.2]); }); describe('lookAt() method 3bits per var', () => { @@ -145,25 +149,25 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { it("Checking lookAt() is found nothing", () => { expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,0,2,3,4,5,6,7]); + expect(ops.vars).toEqual([0,EMPTY,2,3,4,5,6,7]); }); it("Checking lookAt() looking outside of the world - x", () => { - ops.vars[0] = 11; + ops.vars[0] = w + 1; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([11,0,2,3,4,5,6,7]); + expect(ops.vars).toEqual([w + 1,EMPTY,2,3,4,5,6,7]); }); it("Checking lookAt() looking outside of the world - y", () => { - ops.vars[3] = 11; + ops.vars[3] = h + 1; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,0,2,11,4,5,6,7]); + expect(ops.vars).toEqual([0,EMPTY,2,h + 1,4,5,6,7]); }); it('Checking lookAt() found an energy', () => { global.man.world.setDot(0,3,0xaabbcc); expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,1,2,3,4,5,6,7]); + expect(ops.vars).toEqual([0,ENERGY,2,3,4,5,6,7]); global.man.world.setDot(0,3,0); }); @@ -180,7 +184,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(0,3,0xaabbcc); global.man.positions[0][3] = {energy: 123}; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([0,2,2,3,4,5,6,7]); + expect(ops.vars).toEqual([0,ORGANISM,2,3,4,5,6,7]); global.man.world.setDot(0,3,0); global.man.positions[0][3] = 0; }); @@ -189,7 +193,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { ops.vars[0] = .1; ops.vars[3] = .2; expect(ops.operators[hex('101100 001 000 011')].call(ops, 0)).toEqual(1); - expect(ops.vars).toEqual([.1,0,2,.2,4,5,6,7]); + expect(ops.vars).toEqual([.1,EMPTY,2,.2,4,5,6,7]); }); }); }); @@ -208,7 +212,6 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.x).toBe(0); expect(org.y).toBe(1); }); - it("Checking step left with no free space on the left", () => { org.dir = DIRS.LEFT; org.on(EVENTS.STEP, (o,x,y,x1,y1) => { @@ -221,6 +224,60 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.y).toBe(0); }); + it("Checking step right", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 2 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(2); + expect(org.y).toBe(1); + }); + it("Checking step right with no free space on the right", () => { + org.x = w - 1; + org.y = 0; + org.dir = DIRS.RIGHT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === w - 1 && y === 0 && x1 === w && y1 === 0).toBe(true); + o.x = x; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(w - 1); + expect(org.y).toBe(0); + }); + + it("Checking step up", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 0).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(0); + }); + it("Checking step up with no free space on the up", () => { + org.x = 0; + org.y = 0; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === 0 && x1 === 0 && y1 === -1).toBe(true); + o.x = x1; + o.y = y; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(0); + }); + describe('step() operator with 3bits per var', () => { let bpv; let ops; @@ -258,7 +315,6 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.x).toBe(0); expect(org.y).toBe(1); }); - it("Checking step left with no space", () => { org.dir = DIRS.LEFT; org.on(EVENTS.STEP, (o,x,y,x1,y1) => { @@ -270,6 +326,141 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.x).toBe(0); expect(org.y).toBe(0); }); + + it("Checking step right", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 2 && y1 === 1).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(2); + expect(org.y).toBe(1); + }); + it("Checking step right with no free space on the right", () => { + org.x = w - 1; + org.y = 0; + org.dir = DIRS.RIGHT; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === w - 1 && y === 0 && x1 === w && y1 === 0).toBe(true); + o.x = x; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(w - 1); + expect(org.y).toBe(0); + }); + + it("Checking step up", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 0).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(0); + }); + it("Checking step up with no free space on the up", () => { + org.x = 0; + org.y = 0; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === 0 && x1 === 0 && y1 === -1).toBe(true); + o.x = x1; + o.y = y; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(0); + }); + + it("Checking step down", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 2).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(2); + }); + it("Checking step down with no free space on the down", () => { + org.x = 0; + org.y = h - 1; + org.dir = DIRS.DOWN; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === h - 1 && x1 === 0 && y1 === h).toBe(true); + o.x = x1; + o.y = y; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(h - 1); + }); + }); + + it("Checking step up", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 0).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(0); + }); + it("Checking step up with no free space on the up", () => { + org.x = 0; + org.y = 0; + org.dir = DIRS.UP; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === 0 && x1 === 0 && y1 === -1).toBe(true); + o.x = x1; + o.y = y; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(0); + }); + + it("Checking step down", () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 1 && y === 1 && x1 === 1 && y1 === 2).toBe(true); + o.x = x1; + o.y = y1; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(1); + expect(org.y).toBe(2); + }); + it("Checking step down with no free space on the down", () => { + org.x = 0; + org.y = h - 1; + org.dir = DIRS.DOWN; + org.on(EVENTS.STEP, (o,x,y,x1,y1) => { + expect(x === 0 && y === h - 1 && x1 === 0 && y1 === h).toBe(true); + o.x = x1; + o.y = y; + }); + expect(ops.operators[hex('101101')].call(ops, 0, hex('101101'), org)).toEqual(1); + expect(org.x).toBe(0); + expect(org.y).toBe(h - 1); }); }); diff --git a/client/src/manager/plugins/status/charts/Charts.js b/client/src/manager/plugins/status/charts/Charts.js index 66b7541..60a5be2 100644 --- a/client/src/manager/plugins/status/charts/Charts.js +++ b/client/src/manager/plugins/status/charts/Charts.js @@ -184,7 +184,7 @@ class Charts extends Status { * @api */ _transparent(chart, t) { - if (typeof t === 'undefined') { + if (t === undefined) { _each(this._charts, (c, k) => this._setProperty(k, 'transparent', chart)); } else { this._setProperty(chart, 'transparent', t); @@ -234,8 +234,8 @@ class Charts extends Status { * @api */ _active(chart, a) { - const noA = typeof a === 'undefined'; - const noChart = typeof chart === 'undefined'; + const noA = a === undefined; + const noChart = chart === undefined; const bChart = typeof chart === 'boolean'; a = noA ? (bChart ? chart : true) : a; @@ -275,7 +275,7 @@ class Charts extends Status { * @api */ _reset(chart) { - if (typeof chart === 'undefined') { + if (chart === undefined) { _each(this._charts, c => {c.reset(); return true}); } else { _get(this, `_charts.${chart}`, {}).reset && this._charts[chart].reset(); @@ -283,7 +283,7 @@ class Charts extends Status { } _preset(name) { - if (typeof(PRESETS[name]) === 'undefined') {return} + if (PRESETS[name] === undefined) {return} _each(this._charts, (inst, chart) => this._off(chart)); _each(PRESETS[name], (pos, chart) => { @@ -293,7 +293,7 @@ class Charts extends Status { } _setProperty(chart, prop, val) { - if (typeof(this._charts[chart]) === 'undefined') {return} + if (this._charts[chart] === undefined) {return} _has(this.cfg, `charts.${chart}.${prop}`) && (this.cfg.charts[chart][prop] = val); this._charts[chart][prop] = val; } diff --git a/client/src/share/Config.js b/client/src/share/Config.js index c00a417..45e5136 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -11,6 +11,9 @@ const QUIET_IMPORTANT = 1; const QUIET_NO = 2; const ENERGY_COLOR = 10000; +// +// Don't change it to window === undefined, it will trigger an error +// const IS_NODE_JS = typeof window === 'undefined'; class ClientConfig extends Config {} diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index c811522..8446797 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -114,7 +114,7 @@ class Code2JS { } _onBracket(num, line, ops) { - return typeof ops.offs[line] === 'undefined' ? '// }' : '}'; + return ops.offs[line] === undefined ? '// }' : '}'; } _onToMem(num) { diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 5625b86..f2e97c3 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -288,7 +288,7 @@ class Operators { eval(`Operators.global.fn = function call(line, num, org) { const data = num << ${opBits}; const offs = this.funcs[data >>> ${ifBit} === 0 ? Math.round(this.vars[data << 1 >>> ${varBits}]) % ${funcs} : data << 1 >>> ${fnBits}]; - if (typeof offs !== 'undefined') { + if (offs !== undefined) { if (this.stack.length > ${MAX_STACK_SIZE}) { org.energy -= org.vm.size; return ++line; @@ -348,7 +348,7 @@ class Operators { eval(`Operators.global.fn = function bracket(line, num, org, lines) { const startLine = this.offs[line]; - const operator = typeof startLine === 'undefined' ? -1 : lines[startLine] >>> Num.VAR_BITS_OFFS; + const operator = startLine === undefined ? -1 : lines[startLine] >>> Num.VAR_BITS_OFFS; if (operator === 0b100011) {return this.offs[line]} // loop if (operator === 0b100101) { // func const stack = this.stack; diff --git a/client/src/vm/VM.js b/client/src/vm/VM.js index 850deed..73da490 100644 --- a/client/src/vm/VM.js +++ b/client/src/vm/VM.js @@ -100,6 +100,7 @@ class VM extends Observer { const opMask = Num.OPERATOR_MASK_OFF; const weights = this._weights; const lens = Operators.LENS; + const sizeEnergy = OConfig.orgSizeAffectsEnergy; let linesRun = yieldPeriod; let line = this._line; @@ -110,7 +111,7 @@ class VM extends Observer { // // Every operator has it's own weight // - org.vm && (org.energy -= (weights[op] * org.vm.size)); + org.vm && (org.energy -= (weights[op] * (sizeEnergy ? org.vm.size : 1))); // // We reach the end of the script and have to run it from the beginning // diff --git a/common/src/Configurable.js b/common/src/Configurable.js index dd516c9..0aa7c14 100644 --- a/common/src/Configurable.js +++ b/common/src/Configurable.js @@ -64,7 +64,7 @@ class Configurable { const config = cfg.Config; const cls = Helper.loverCase(this.constructor.name); - if (typeof config[cls] !== 'undefined') { + if (config[cls] !== undefined) { throw `Looks like there are two plugins with the same name try to set their configuration. Name: ${cls}`; } @@ -83,7 +83,7 @@ class Configurable { const api = this._parent.api; const cls = Helper.loverCase(this.constructor.name); - if (typeof api[cls] !== 'undefined') { + if (api[cls] !== undefined) { throw `Looks like there are two plugins with the same name try to set their configuration. Name: ${cls}`; } diff --git a/common/src/Helper.js b/common/src/Helper.js index 077a9de..aeee238 100644 --- a/common/src/Helper.js +++ b/common/src/Helper.js @@ -61,7 +61,7 @@ class Helper { // reference to fn.fn and this code crashes on line `fn.fn.apply(obj, args)` // const oldFn = fn.fn = obj[fnName]; - if (typeof oldFn === 'undefined') {throw `Helper.override: Parent object doesn't contain method '${fnName}'`} + if (oldFn === undefined) {throw `Helper.override: Parent object doesn't contain method '${fnName}'`} if (!hard) { obj[fnName] = (...args) => { const ret = fn(...args); @@ -234,7 +234,7 @@ class Helper { const xMap = {0: Config.worldWidth - 1, [Config.worldWidth - 1]: 0}; const yMap = {0: Config.worldHeight - 1, [Config.worldHeight - 1]: 0}; - return [(dir === DIR.LEFT || dir === DIR.RIGHT) && typeof(xMap[x]) !== 'undefined' ? xMap[x] : x, (dir === DIR.UP || dir === DIR.DOWN) && typeof(yMap[y]) !== 'undefined' ? yMap[y] : y]; + return [(dir === DIR.LEFT || dir === DIR.RIGHT) && xMap[x] !== undefined ? xMap[x] : x, (dir === DIR.UP || dir === DIR.DOWN) && yMap[y] !== undefined ? yMap[y] : y]; } /** diff --git a/common/src/Observer.js b/common/src/Observer.js index 97e879c..15c11fc 100644 --- a/common/src/Observer.js +++ b/common/src/Observer.js @@ -28,7 +28,7 @@ class Observer { on(event, handler) { const eventObj = this._handlers[event]; - if (typeof(eventObj) === 'undefined') {return false} + if (eventObj === undefined) {return false} eventObj[eventObj.amount++] = handler; return true; diff --git a/common/src/plugins/Request.js b/common/src/plugins/Request.js index 949aabb..f5c0433 100644 --- a/common/src/plugins/Request.js +++ b/common/src/plugins/Request.js @@ -111,7 +111,7 @@ class Request { * @param {String} error Error message */ _onSendErr(error) { - if (typeof error !== 'undefined') { + if (error !== undefined) { Console.error(`Request.send() error: ${error}`); } } From 08ee7b23439b311759a087b9cde0d39ae5fe0d7f Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 21 Jun 2018 22:32:16 +0300 Subject: [PATCH 65/88] added test for eat operator #145 --- .../src/manager/plugins/organisms/Config.js | 2 +- .../plugins/organisms/dos/Operators.js | 13 ++-- .../plugins/organisms/dos/OperatorsSpec.js | 73 +++++++++++++++++++ 3 files changed, 80 insertions(+), 8 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index a39ff4d..ec69b48 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -182,7 +182,7 @@ const Config = { * default value, while organism is delivering. So, if the value is * 1000, then range will be: -500..500 */ - codeVarInitRange: 10000000, + codeVarInitRange: 1000, /** * {Number} This value is amount of code lines, which will be run for one * organism without interruption by one VM. Set this value to value bigger diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 0da2a3e..c0c45f3 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -241,14 +241,14 @@ class OperatorsDos extends Operators { if ((eat = this._world.grabDot(x, y, eat)) > 0) { if (org.energy + eat > OConfig.orgMaxEnergy) {eat = OConfig.orgMaxEnergy - org.energy} org.energy += eat; - this._obs.fire(EVENTS.EAT_ENERGY, eat); + this._obs.fire(${EVENTS.EAT_ENERGY}, eat); } return ++line; } if (victim.energy <= eat) { // Organism found if (org.energy + victim.energy > OConfig.orgMaxEnergy) {return ++line} - this._obs.fire(EVENTS.KILL_EAT, victim); - org.energy += victim.energy; + this._obs.fire(${EVENTS.KILL_EAT}, victim); + org.energy += victim.energy; // // IMPORTANT: // We have to do destroy here, to have a possibility for current @@ -260,7 +260,7 @@ class OperatorsDos extends Operators { } if (org.energy + eat > OConfig.orgMaxEnergy) {return ++line} - this._obs.fire(EVENTS.EAT_ORG, victim, eat); + this._obs.fire(${EVENTS.EAT_ORG}, victim, eat); org.energy += eat; victim.energy -= eat; @@ -286,7 +286,6 @@ class OperatorsDos extends Operators { const h = Helper.toHexNum; const b = Helper.toBinStr; const vars = Math.pow(2, bpv); - const event = EVENTS.PUT_ENERGY; for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function put(line, num, org) { @@ -300,13 +299,13 @@ class OperatorsDos extends Operators { if (org.energy <= put) { put = org.energy; this._world.setDot(x, y, put); - this._obs.fire(${event}, put); + this._obs.fire(${EVENTS.PUT_ENERGY}, put); org.destroy(); return ++line; } this._world.setDot(x, y, put); - this._obs.fire(${event}, put); + this._obs.fire(${EVENTS.PUT_ENERGY}, put); org.energy -= put; return ++line; }`); diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 862954a..03f1673 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -846,6 +846,13 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([1, 0, 1, 2]); expect(org.energy).toEqual(energy); }); + it("Checking eating negative value", () => { + const energy = org.energy; + ops.vars = [-1, 0, 1, 2]; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([-1, 0, 1, 2]); + expect(org.energy).toEqual(energy); + }); it("Checking eating energy", () => { org.energy = 1; @@ -858,6 +865,17 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([1, 0, 1, 2]); expect(org.energy).toEqual(2); }); + it("Checking eating energy more then OConfig.orgMaxEnergy", () => { + org.energy = 1; + ops.vars = [100, 0, 1, 2]; + ops.world.setDot(1,0,100); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([100, 0, 1, 2]); + expect(org.energy).toEqual(100); + }); it("Checking eating world object", () => { org.energy = 1; @@ -901,6 +919,24 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.energy).toEqual(2); expect(org2.energy).toEqual(energy - 1); + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); + it("Checking eating and kill other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + const energy = org2.energy = 1; + org.energy = 1; + ops.vars = [energy, 0, 1, 2]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110001 00')].call(ops, 0, hex('110001 00'), org)).toEqual(1); + expect(ops.vars).toEqual([energy, 0, 1, 2]); + expect(org.energy).toEqual(2); + expect(org2.energy).toEqual(0); + expect(org2.vm).toEqual(null); global.man.positions[1][0] = 0; ops.world.setDot(1,0,0); @@ -944,6 +980,14 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6, 7]); expect(org.energy).toEqual(energy); }); + it("Checking eating negative value", () => { + const energy = org.energy; + ops.vars = [-1, 0, 1, 2, 3, 4, 5, 6]; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([-1, 0, 1, 2, 3, 4, 5, 6]); + expect(org.energy).toEqual(energy); + }); + it("Checking eating energy", () => { org.energy = 1; ops.vars = [1, 0, 1, 2, 3, 4, 5, 6, 7]; @@ -955,6 +999,17 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([1, 0, 1, 2, 3, 4, 5, 6, 7]); expect(org.energy).toEqual(2); }); + it("Checking eating energy more then OConfig.orgMaxEnergy", () => { + org.energy = 1; + ops.vars = [100, 0, 1, 2, 3, 4, 5, 6]; + ops.world.setDot(1,0,100); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([100, 0, 1, 2, 3, 4, 5, 6]); + expect(org.energy).toEqual(100); + }); it("Checking eating world object", () => { org.energy = 1; @@ -998,6 +1053,24 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org.energy).toEqual(2); expect(org2.energy).toEqual(energy - 1); + global.man.positions[1][0] = 0; + ops.world.setDot(1,0,0); + }); + it("Checking eating and kill other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + const energy = org2.energy = 1; + org.energy = 1; + ops.vars = [energy, 0, 1, 2, 3, 4, 5, 6]; + ops.world.setDot(1,0,10); + org.dir = DIRS.UP; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110001 000')].call(ops, 0, hex('110001 000'), org)).toEqual(1); + expect(ops.vars).toEqual([energy, 0, 1, 2, 3, 4, 5, 6]); + expect(org.energy).toEqual(2); + expect(org2.energy).toEqual(0); + expect(org2.vm).toEqual(null); global.man.positions[1][0] = 0; ops.world.setDot(1,0,0); From 0cc63f2b7a674f48e91700245b3b03944c1d8768 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 22 Jun 2018 00:03:33 +0300 Subject: [PATCH 66/88] added test for energy operator #145 --- .../src/manager/plugins/organisms/Config.js | 4 +- .../plugins/organisms/dos/Operators.js | 2 +- .../plugins/organisms/dos/OperatorsSpec.js | 201 ++++++++++++++++++ client/src/share/Config.js | 2 +- 4 files changed, 205 insertions(+), 4 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index ec69b48..cb2fd1c 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -116,13 +116,13 @@ const Config = { /** * {Number} Maximum energy organism may reach collecting energy */ - orgMaxEnergy: 10 * ENERGY_VALUE, + orgMaxEnergy: 20 * ENERGY_VALUE, /** * {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: 10 * ENERGY_VALUE, + orgStartEnergy: 20 * ENERGY_VALUE, /** * {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/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index c0c45f3..45c0b57 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -358,7 +358,7 @@ class OperatorsDos extends Operators { for (let e = 1, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e <= len; e++) { if (energy[e].length === 4) { const xy = energy[e]; - let eat = (2**(e+1)) * Helper.getColor(EConfig.colorIndex); + let eat = (2**e) * Helper.getColor(EConfig.colorIndex); if (org.energy + eat > OConfig.orgMaxEnergy) {eat = OConfig.orgMaxEnergy - org.energy} org.energy += eat; diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 03f1673..d1cd8ac 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1,6 +1,7 @@ const _fill = require('lodash/fill'); const OperatorsDos = require('./Operators'); const OConfig = require('./../../../plugins/organisms/Config'); +const EConfig = require('./../../../plugins/energy/Config'); const Config = require('./../../../../share/Config').Config; const Helper = require('./../../../../../../common/src/Helper'); const OrganismDos = require('./Organism'); @@ -1253,6 +1254,206 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); + describe('energy() operator', () => { + let maxEnergy = OConfig.orgMaxEnergy; + beforeEach(() => OConfig.orgMaxEnergy = Helper.getColor(EConfig.colorIndex) * 32); + afterEach (() => OConfig.orgMaxEnergy = maxEnergy); + + it("Checking energy nothing", () => { + const energy = org.energy; + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + expect(org.energy).toEqual(energy); + }); + + it("Two dots of e0 should give 2x energy 1", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(1,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 2", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(2,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 3", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeeee); + global.man.world.setDot(2,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 4", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(0,1,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 5", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(0,2,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 6", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,1,0xeeeeee); + global.man.world.setDot(2,1,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 7", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(2,2,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[2][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,2)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 8", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,2,0xeeeeee); + global.man.world.setDot(2,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + }); + it("Two dots of e0 should give 2x energy 8", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[2][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(2,1,0xeeeeee); + global.man.world.setDot(2,2,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.positions[2][2]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(global.man.world.getDot(2,2)).toEqual(EMPTY); + }); + + it("Two dots of e0 should not give 2x energy if they are distant 1", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[3][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeeee); + global.man.world.setDot(3,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[1][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[3][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeeee); + expect(global.man.world.getDot(3,0)).toEqual(0xeeeeee); + + global.man.positions[1][0] = EMPTY; + global.man.positions[3][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); + global.man.world.setDot(3,0,EMPTY); + }); + it("Two dots of e0 should not give 2x energy if they are distant 2", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][3] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(0,3,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[0][3]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(0,0)).toEqual(0xeeeeee); + expect(global.man.world.getDot(0,3)).toEqual(0xeeeeee); + + global.man.positions[0][0] = EMPTY; + global.man.positions[0][3] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + global.man.world.setDot(0,3,EMPTY); + }); + }); + xdescribe('onCheckLeft() method', () => { let org; let ops; diff --git a/client/src/share/Config.js b/client/src/share/Config.js index 45e5136..faaaa62 100644 --- a/client/src/share/Config.js +++ b/client/src/share/Config.js @@ -70,7 +70,7 @@ ClientConfig.init({ * {Number} Amount of all energy in a world including organisms and all kinds * of energy. Total energy should not be greater then this value. */ - worldEnergy: 0x6d3b4 * 10000 * 10, // Helper.getColor(ENERGY_COLOR) === 0x6d3b4 + worldEnergy: 0x6d3b4 * 10000 * 20, // Helper.getColor(ENERGY_COLOR) === 0x6d3b4 /** * {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 0ac0329b9e7a9b80cec368aa9c55891634e70f8d Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 22 Jun 2018 23:05:08 +0300 Subject: [PATCH 67/88] added test for energy operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index d1cd8ac..8ebe2f6 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1452,6 +1452,81 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(0,0,EMPTY); global.man.world.setDot(0,3,EMPTY); }); + + it("One e0 and one e1 should not give 2x energy", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,2,0xeeeee0); + global.man.world.setDot(2,0,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][2]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.world.getDot(0,2)).toEqual(0xeeeee0); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeee1); + + global.man.positions[0][2] = EMPTY; + global.man.positions[2][0] = EMPTY; + global.man.world.setDot(0,2,EMPTY); + global.man.world.setDot(2,0,EMPTY); + }); + + describe("Three dots should create new energy element - e1", () => { + it("Two e0 should create one e1", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(1,0,0xeeeeee); + global.man.world.setDot(2,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0) > 0).toEqual(true); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + }); + it("Four e0 should create one e1 and one e0", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(1,0,0xeeeeee); + global.man.world.setDot(2,0,0xeeeeee); + global.man.world.setDot(0,1,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0) > 0).toEqual(true); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeeee); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + }); + }); }); xdescribe('onCheckLeft() method', () => { From a3c8ac31da375778d2abfd3a45d4f3c92bb13374 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Fri, 22 Jun 2018 23:08:47 +0300 Subject: [PATCH 68/88] added test for energy operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 8ebe2f6..6710fc3 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1475,7 +1475,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(2,0,EMPTY); }); - describe("Three dots should create new energy element - e1", () => { + describe("e1 relates tests", () => { it("Two e0 should create one e1", () => { const energy = org.energy = 1; org.x = 1; @@ -1526,6 +1526,26 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[0][0] = EMPTY; global.man.world.setDot(0,0,EMPTY); }); + + it("Two e1 should give 4x energy increase", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(1,0,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + }); }); }); From 6e7aaba821884c0c772558654b0474fb235ed18b Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 23 Jun 2018 12:10:52 +0300 Subject: [PATCH 69/88] added test for energy operator #145 --- .../plugins/organisms/dos/Operators.js | 8 +- .../plugins/organisms/dos/OperatorsSpec.js | 226 +++++++++++++++++- 2 files changed, 228 insertions(+), 6 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 45c0b57..4eb7a66 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -334,7 +334,9 @@ class OperatorsDos extends Operators { const world = this._world; const energy = {1:[], 2:[], 3:[], 4:[], 5:[]}; let e = 0; - + // + // this block creates new energy object + // for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { @@ -354,7 +356,9 @@ class OperatorsDos extends Operators { } } } - + // + // this block changes two energy objects into organism energy + // for (let e = 1, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e <= len; e++) { if (energy[e].length === 4) { const xy = energy[e]; diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 6710fc3..e955edf 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1474,9 +1474,32 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(0,2,EMPTY); global.man.world.setDot(2,0,EMPTY); }); + it("One e1 and two e0 should give 2x energy", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(0,1,0xeeeee0); + global.man.world.setDot(0,2,0xeeeee0); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 2); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(0xeeeee1); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + }); describe("e1 relates tests", () => { - it("Two e0 should create one e1", () => { + it("Three e0 should create one e1", () => { const energy = org.energy = 1; org.x = 1; org.y = 1; @@ -1527,14 +1550,14 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(0,0,EMPTY); }); - it("Two e1 should give 4x energy increase", () => { + it("Two e1 should give 4x energy increase 1", () => { const energy = org.energy = 1; org.x = 1; org.y = 1; global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.world.setDot(0,0,0xeeeeee); - global.man.world.setDot(1,0,0xeeeeee); + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(1,0,0xeeeee1); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); @@ -1542,10 +1565,205 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(global.man.positions[1][0]).toEqual(EMPTY); expect(global.man.world.getDot(0,0)).toEqual(EMPTY); expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + }); + it("Two e1 should give 4x energy increase 2", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(2,0,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + }); + it("Two e1 should give 4x energy increase 3", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(0,1,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + }); + it("Two e1 should give 4x energy increase 4", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(0,2,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + }); + it("Two e1 should give 4x energy increase 4", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[2][2] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(2,2,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[2][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,2)).toEqual(EMPTY); + }); + }); + + describe("e4 relates tests", () => { + it("Three e3 should create one e4", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.world.setDot(0,0,0xeeeee3); + global.man.world.setDot(1,0,0xeeeee3); + global.man.world.setDot(2,0,0xeeeee3); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY4); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0) > 0).toEqual(true); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); global.man.positions[0][0] = EMPTY; global.man.world.setDot(0,0,EMPTY); }); + xit("Four e0 should create one e1 and one e0", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeeee); + global.man.world.setDot(1,0,0xeeeeee); + global.man.world.setDot(2,0,0xeeeeee); + global.man.world.setDot(0,1,0xeeeeee); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0) > 0).toEqual(true); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeeee); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + }); + + xit("Two e1 should give 4x energy increase 1", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(1,0,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + }); + xit("Two e1 should give 4x energy increase 2", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(2,0,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + }); + xit("Two e1 should give 4x energy increase 3", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(0,1,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + }); + xit("Two e1 should give 4x energy increase 4", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(0,2,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + }); + xit("Two e1 should give 4x energy increase 4", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.positions[2][2] = OBJECT_TYPES.TYPE_ENERGY1; + global.man.world.setDot(0,0,0xeeeee1); + global.man.world.setDot(2,2,0xeeeee1); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[2][2]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,2)).toEqual(EMPTY); + }); }); }); From 2b3d8feffb2ea5da3d0ae8ae10732ef1c423f173 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 23 Jun 2018 14:00:23 +0300 Subject: [PATCH 70/88] added tests for eat operator #145 --- .../plugins/organisms/dos/Operators.js | 6 +- .../plugins/organisms/dos/OperatorsSpec.js | 159 ++++++++++++------ 2 files changed, 115 insertions(+), 50 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 4eb7a66..17348aa 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -339,7 +339,7 @@ class OperatorsDos extends Operators { // for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { - if (IN_WORLD(x, y) && poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4) { + if (IN_WORLD(x, y) && poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4}) { e = -poses[x][y]; energy[e].push(x, y); if (energy[e].length === 6) { @@ -359,7 +359,7 @@ class OperatorsDos extends Operators { // // this block changes two energy objects into organism energy // - for (let e = 1, len = Math.abs(OBJECT_TYPES.TYPE_ENERGY4 - OBJECT_TYPES.TYPE_ENERGY0) + 1; e <= len; e++) { + for (let e = 1, len = Math.abs(${OBJECT_TYPES.TYPE_ENERGY4} - ${OBJECT_TYPES.TYPE_ENERGY0}) + 1; e <= len; e++) { if (energy[e].length === 4) { const xy = energy[e]; let eat = (2**e) * Helper.getColor(EConfig.colorIndex); @@ -402,7 +402,7 @@ class OperatorsDos extends Operators { const world = this._world; const x = org.dirX; const y = org.dirY; - if (IN_WORLD(x, y) && (poses[x][y] <= OBJECT_TYPES.TYPE_ENERGY0 && poses[x][y] >= OBJECT_TYPES.TYPE_ENERGY4 || poses[x][y] === 0 && world.data[x][y] > 0)) { + if (IN_WORLD(x, y) && (poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4} || poses[x][y] === 0 && world.data[x][y] > 0)) { const dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; const dx = org.x + OFFSX[dir]; const dy = org.y + OFFSY[dir]; diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index e955edf..5bddabb 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1656,115 +1656,180 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[0][0] = EMPTY; global.man.world.setDot(0,0,EMPTY); }); - xit("Four e0 should create one e1 and one e0", () => { + it("Four e3 should create one e4 and one e3", () => { const energy = org.energy = 1; org.x = 1; org.y = 1; - global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; - global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; - global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; - global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; - global.man.world.setDot(0,0,0xeeeeee); - global.man.world.setDot(1,0,0xeeeeee); - global.man.world.setDot(2,0,0xeeeeee); - global.man.world.setDot(0,1,0xeeeeee); + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY3; + global.man.world.setDot(0,0,0xeeeee3); + global.man.world.setDot(1,0,0xeeeee3); + global.man.world.setDot(2,0,0xeeeee3); + global.man.world.setDot(0,1,0xeeeee3); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); expect(org.energy).toEqual(energy); - expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY4); expect(global.man.positions[1][0]).toEqual(EMPTY); - expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY3); expect(global.man.positions[0][1]).toEqual(EMPTY); expect(global.man.world.getDot(0,0) > 0).toEqual(true); expect(global.man.world.getDot(1,0)).toEqual(EMPTY); - expect(global.man.world.getDot(2,0)).toEqual(0xeeeeee); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeee3); expect(global.man.world.getDot(0,1)).toEqual(EMPTY); global.man.positions[0][0] = EMPTY; global.man.world.setDot(0,0,EMPTY); }); - xit("Two e1 should give 4x energy increase 1", () => { - const energy = org.energy = 1; + it("Two e4 should give 32x energy increase 1", () => { + const energy = org.energy = 0; // shouldn't be more then 0 org.x = 1; org.y = 1; - global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.world.setDot(0,0,0xeeeee1); - global.man.world.setDot(1,0,0xeeeee1); + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.world.setDot(0,0,0xeeeee4); + global.man.world.setDot(1,0,0xeeeee4); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); - expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 32); expect(global.man.positions[0][0]).toEqual(EMPTY); expect(global.man.positions[1][0]).toEqual(EMPTY); expect(global.man.world.getDot(0,0)).toEqual(EMPTY); expect(global.man.world.getDot(1,0)).toEqual(EMPTY); }); - xit("Two e1 should give 4x energy increase 2", () => { - const energy = org.energy = 1; + it("Two e4 should give 32x energy increase 2", () => { + const energy = org.energy = 0; org.x = 1; org.y = 1; - global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.world.setDot(0,0,0xeeeee1); - global.man.world.setDot(2,0,0xeeeee1); + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.world.setDot(0,0,0xeeeee4); + global.man.world.setDot(2,0,0xeeeee4); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); - expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 32); expect(global.man.positions[0][0]).toEqual(EMPTY); expect(global.man.positions[2][0]).toEqual(EMPTY); expect(global.man.world.getDot(0,0)).toEqual(EMPTY); expect(global.man.world.getDot(2,0)).toEqual(EMPTY); }); - xit("Two e1 should give 4x energy increase 3", () => { - const energy = org.energy = 1; + it("Two e4 should give 32x energy increase 3", () => { + const energy = org.energy = 0; org.x = 1; org.y = 1; - global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.world.setDot(0,0,0xeeeee1); - global.man.world.setDot(0,1,0xeeeee1); + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.world.setDot(0,0,0xeeeee4); + global.man.world.setDot(0,1,0xeeeee4); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); - expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 32); expect(global.man.positions[0][0]).toEqual(EMPTY); expect(global.man.positions[0][1]).toEqual(EMPTY); expect(global.man.world.getDot(0,0)).toEqual(EMPTY); expect(global.man.world.getDot(0,1)).toEqual(EMPTY); }); - xit("Two e1 should give 4x energy increase 4", () => { - const energy = org.energy = 1; + it("Two e4 should give 32x energy increase 4", () => { + const energy = org.energy = 0; org.x = 1; org.y = 1; - global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.world.setDot(0,0,0xeeeee1); - global.man.world.setDot(0,2,0xeeeee1); + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.world.setDot(0,0,0xeeeee4); + global.man.world.setDot(0,2,0xeeeee4); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); - expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 32); expect(global.man.positions[0][0]).toEqual(EMPTY); expect(global.man.positions[0][2]).toEqual(EMPTY); expect(global.man.world.getDot(0,0)).toEqual(EMPTY); expect(global.man.world.getDot(0,2)).toEqual(EMPTY); }); - xit("Two e1 should give 4x energy increase 4", () => { - const energy = org.energy = 1; + it("Two e4 should give 32x energy increase 5", () => { + const energy = org.energy = 0; org.x = 1; org.y = 1; - global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.positions[2][2] = OBJECT_TYPES.TYPE_ENERGY1; - global.man.world.setDot(0,0,0xeeeee1); - global.man.world.setDot(2,2,0xeeeee1); + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.positions[2][2] = OBJECT_TYPES.TYPE_ENERGY4; + global.man.world.setDot(0,0,0xeeeee4); + global.man.world.setDot(2,2,0xeeeee4); expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); - expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 32); expect(global.man.positions[0][0]).toEqual(EMPTY); expect(global.man.positions[2][2]).toEqual(EMPTY); expect(global.man.world.getDot(0,0)).toEqual(EMPTY); expect(global.man.world.getDot(2,2)).toEqual(EMPTY); }); }); + + describe("Complex energy objects scenarios", () => { + it("Six e0 should give two e1", () => { + const energy = org.energy = 1; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[0][2] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.positions[2][1] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeee0); + global.man.world.setDot(1,0,0xeeeee0); + global.man.world.setDot(2,0,0xeeeee0); + global.man.world.setDot(0,1,0xeeeee0); + global.man.world.setDot(0,2,0xeeeee0); + global.man.world.setDot(2,1,0xeeeee0); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[1][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(0,0) > 0).toEqual(true); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeee0); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee0); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy); + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[1][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY1); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0) > 0).toEqual(true); + expect(global.man.world.getDot(1,0) > 0).toEqual(true); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110011')].call(ops, 0, hex('110011'), org)).toEqual(1); + + expect(org.energy).toEqual(energy + Helper.getColor(EConfig.colorIndex) * 4); + expect(global.man.positions[0][0]).toEqual(EMPTY); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.positions[2][0]).toEqual(EMPTY); + expect(global.man.positions[0][1]).toEqual(EMPTY); + expect(global.man.positions[0][2]).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(0,0)).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.world.getDot(2,0)).toEqual(EMPTY); + expect(global.man.world.getDot(0,1)).toEqual(EMPTY); + expect(global.man.world.getDot(0,2)).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + }); + }); }); xdescribe('onCheckLeft() method', () => { From c621bd407c268d9fea2d03c04483581a6b2d5c7e Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 23 Jun 2018 15:21:26 +0300 Subject: [PATCH 71/88] added myDir operator --- .../plugins/organisms/dos/Operators.js | 58 ++++++++++++++----- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 17348aa..1eb6601 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -37,7 +37,7 @@ class OperatorsDos extends Operators { /** * {Number} Total amount of operators. Base lang + custom */ - this.OPERATOR_AMOUNT = 26; + this.OPERATOR_AMOUNT = 27; // // IMPORTANT: don't use super here, because it breaks Operators // IMPORTANT: class internal logic. Operators.global will be point @@ -45,20 +45,21 @@ class OperatorsDos extends Operators { // Operators.compile(this.OPERATOR_AMOUNT); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); - this.LENS.push(Num.MAX_BITS - bitsPerOp); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - bitsPerOp); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // say - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); - this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar * 3)); // lookAt + this.LENS.push(Num.MAX_BITS - bitsPerOp); // step + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // dir + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // myX + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // myY + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // eat + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // put + this.LENS.push(Num.MAX_BITS - bitsPerOp); // energy + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // pick + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // say + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // listen + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // check + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // myEnergy + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // myAge + this.LENS.push(Num.MAX_BITS - (bitsPerOp + OConfig.codeBitsPerVar)); // myDir this._compileLookAt(); // 12 this._compileStep(); // 13 @@ -74,6 +75,7 @@ class OperatorsDos extends Operators { this._compileCheck(); // 23 this._compileMyEnergy(); // 24 this._compileMyAge(); // 25 + this._compileMyDir(); // 26 } /** @@ -558,6 +560,32 @@ class OperatorsDos extends Operators { } } + /** + * Compiles all variants of 'myDir' operator and stores they in + * this._compiledOperators map. '...' means, that all other bits are + * ignored. Step direction depends on active organism's direction. + * See Organism.dir property. Example: + * + * bits : 6 xx + * number: 111010 00... + * string: v0 = myDir() + */ + static _compileMyDir() { + const bpv = OConfig.codeBitsPerVar; + const ops = this._compiledOperators; + const h = Helper.toHexNum; + const b = Helper.toBinStr; + const vars = Math.pow(2, bpv); + + for (let v0 = 0; v0 < vars; v0++) { + eval(`Operators.global.fn = function myDir(line, num, org) { + this.vars[${v0}] = org.dir; + return ++line; + }`); + ops[h(`${'111010'}${b(v0, bpv)}`)] = this.global.fn; + } + } + constructor(offs, vars, obs) { super(offs, vars, obs); /** From 0eefcd82da87a90f0fa2eed2c8f9a206b565eb56 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 23 Jun 2018 20:33:25 +0300 Subject: [PATCH 72/88] added test for pick operator #145 --- .../plugins/organisms/dos/Operators.js | 6 +- .../plugins/organisms/dos/OperatorsSpec.js | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 1eb6601..9f5f687 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -149,11 +149,10 @@ class OperatorsDos extends Operators { const h = Helper.toHexNum; const b = Helper.toBinStr; const vars = Math.pow(2, bpv); - const dirs = OFFSX.length; for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function dir(line, num, org) { - org.dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; + org.dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${OFFSX.length}; return ++line; }`); ops[h(`${'101110'}${b(v0, bpv)}`)] = this.global.fn; @@ -396,7 +395,6 @@ class OperatorsDos extends Operators { const h = Helper.toHexNum; const b = Helper.toBinStr; const vars = Math.pow(2, bpv); - const dirs = OFFSX.length; for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function pick(line, num, org) { @@ -405,7 +403,7 @@ class OperatorsDos extends Operators { const x = org.dirX; const y = org.dirY; if (IN_WORLD(x, y) && (poses[x][y] <= ${OBJECT_TYPES.TYPE_ENERGY0} && poses[x][y] >= ${OBJECT_TYPES.TYPE_ENERGY4} || poses[x][y] === 0 && world.data[x][y] > 0)) { - const dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${dirs}; + const dir = ((this.vars[${v0}] + .5) << 0 >>> 0) % ${OFFSX.length}; const dx = org.x + OFFSX[dir]; const dy = org.y + OFFSY[dir]; if (IN_WORLD(dx, dy) && world.data[dx][dy] === 0) { diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 5bddabb..a592d4f 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1832,6 +1832,67 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); + describe('pick() operator', () => { + it("Checking picking from up to right", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[2][1]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee0); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + it("Checking picking out of the world", () => { + org.x = 1; + org.y = 0; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeee0); + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(2,0,0xeeeee0); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(0,0)).toEqual(0xeeeee0); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeee0); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + global.man.positions[2][0] = EMPTY; + global.man.world.setDot(2,0,EMPTY); + }); + + it("Checking picking other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.positions[1][0] = org2; + global.man.world.setDot(1,0,0xeeeee0); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(org2); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + + global.man.positions[1][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); + org2.destroy(); + }); + }); + xdescribe('onCheckLeft() method', () => { let org; let ops; From b15ea5732268f0d1bab3b222d2b8fb94e267d160 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 23 Jun 2018 21:17:11 +0300 Subject: [PATCH 73/88] added test for pick operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 101 +++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index a592d4f..d283726 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -8,6 +8,7 @@ const OrganismDos = require('./Organism'); const World = require('./../../../../view/World').World; const EVENTS = require('./../../../../share/Events').EVENTS; const DIRS = require('./../../../../../../common/src/Directions').DIR; +const OFFSX = require('./../../../../../../common/src/Directions').OFFSX; const OBJECT_TYPES = require('./../../../../view/World').OBJECT_TYPES; const EMPTY = 0; @@ -1833,7 +1834,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); describe('pick() operator', () => { - it("Checking picking from up to right", () => { + it("Checking picking from up to right 1", () => { org.x = 1; org.y = 1; ops.vars[0] = DIRS.RIGHT; @@ -1844,12 +1845,53 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(global.man.world.getDot(2,1)).toEqual(EMPTY); expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); expect(global.man.positions[2][1]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); expect(global.man.world.getDot(2,1)).toEqual(0xeeeee0); global.man.positions[2][1] = EMPTY; global.man.world.setDot(2,1,EMPTY); }); + it("Checking picking from up to right 2", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT + OFFSX.length; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee0); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + it("Checking picking from up to down", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.DOWN; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[1][2]).toEqual(EMPTY); + expect(global.man.world.getDot(1,2)).toEqual(EMPTY); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[1][2]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(1,2)).toEqual(0xeeeee0); + + global.man.positions[1][2] = EMPTY; + global.man.world.setDot(1,2,EMPTY); + }); + it("Checking picking out of the world", () => { org.x = 1; org.y = 0; @@ -1891,6 +1933,63 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(1,0,EMPTY); org2.destroy(); }); + + it("Checking picking simple energy", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xeeeeee); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeeee); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + + it("Checking impossible picking simple energy", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xeeeee0); + global.man.world.setDot(2,1,0xeeeee1); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee1); + + global.man.positions[1][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + + it("Checking picking from up to up", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.UP; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110100 00')].call(ops, 0, hex('110100 00'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); }); xdescribe('onCheckLeft() method', () => { From 25dad998d6c554e398c7c6ebdc030fec5f0cf545 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sat, 23 Jun 2018 21:29:45 +0300 Subject: [PATCH 74/88] added test for pick operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index d283726..4aa2984 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1990,6 +1990,188 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.positions[2][1] = EMPTY; global.man.world.setDot(2,1,EMPTY); }); + + describe('pick() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking picking from up to right 1", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee0); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + it("Checking picking from up to right 2", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT + OFFSX.length; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee0); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + it("Checking picking from up to down", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.DOWN; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[1][2]).toEqual(EMPTY); + expect(global.man.world.getDot(1,2)).toEqual(EMPTY); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[1][2]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(1,2)).toEqual(0xeeeee0); + + global.man.positions[1][2] = EMPTY; + global.man.world.setDot(1,2,EMPTY); + }); + + it("Checking picking out of the world", () => { + org.x = 1; + org.y = 0; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.positions[0][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(0,0,0xeeeee0); + global.man.positions[2][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(2,0,0xeeeee0); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[0][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.positions[2][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(0,0)).toEqual(0xeeeee0); + expect(global.man.world.getDot(2,0)).toEqual(0xeeeee0); + + global.man.positions[0][0] = EMPTY; + global.man.world.setDot(0,0,EMPTY); + global.man.positions[2][0] = EMPTY; + global.man.world.setDot(2,0,EMPTY); + }); + + it("Checking picking other organism", () => { + const org2 = new OrganismDos(1, 0, 0, {}); + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.positions[1][0] = org2; + global.man.world.setDot(1,0,0xeeeee0); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(org2); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + + global.man.positions[1][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); + org2.destroy(); + }); + + it("Checking picking simple energy", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xeeeeee); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(EMPTY); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeeee); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + + it("Checking impossible picking simple energy", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.RIGHT; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xeeeee0); + global.man.world.setDot(2,1,0xeeeee1); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(0xeeeee1); + + global.man.positions[1][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + + it("Checking picking from up to up", () => { + org.x = 1; + org.y = 1; + ops.vars[0] = DIRS.UP; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + global.man.world.setDot(1,0,0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + expect(ops.operators[hex('110100 000')].call(ops, 0, hex('110100 000'), org)).toEqual(1); + + expect(global.man.positions[1][0]).toEqual(OBJECT_TYPES.TYPE_ENERGY0); + expect(global.man.world.getDot(1,0)).toEqual(0xeeeee0); + expect(global.man.positions[2][1]).toEqual(EMPTY); + expect(global.man.world.getDot(2,1)).toEqual(EMPTY); + + global.man.positions[2][1] = EMPTY; + global.man.world.setDot(2,1,EMPTY); + }); + }); }); xdescribe('onCheckLeft() method', () => { From b8505c26ce29cd5fc364f8af78f295b045fc66b3 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 24 Jun 2018 19:32:41 +0300 Subject: [PATCH 75/88] small fix --- client/src/manager/plugins/organisms/dos/OperatorsSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 5bddabb..1cdd0e4 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1767,7 +1767,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); describe("Complex energy objects scenarios", () => { - it("Six e0 should give two e1", () => { + it("Six e0 should give two e1 and 4x energy", () => { const energy = org.energy = 1; org.x = 1; org.y = 1; From ce5635355305545059d95550f9110feb4c3b1334 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 24 Jun 2018 20:36:22 +0300 Subject: [PATCH 76/88] added test for 'say' operator #145 from now, 'say' command works for all around organisms, not only one --- .../plugins/organisms/dos/Operators.js | 10 ++- .../plugins/organisms/dos/OperatorsSpec.js | 74 ++++++++++++++++++- 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 9f5f687..814aa5e 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -438,9 +438,13 @@ class OperatorsDos extends Operators { for (let v0 = 0; v0 < vars; v0++) { eval(`Operators.global.fn = function say(line, num, org) { - let x = org.dirX; - let y = org.dirY; - IN_WORLD(x, y) && !(this._positions[x][y] <= 0) && (this._positions[x][y].msg = this.vars[${v0}]); + const poses = this._positions; + + for (let x = org.x - 1, xlen = org.x + 2; x < xlen; x++) { + for (let y = org.y - 1, ylen = org.y + 2; y < ylen; y++) { + IN_WORLD(x, y) && !(poses[x][y] <= 0) && (poses[x][y].msg = this.vars[${v0}]); + } + } return ++line; }`); ops[h(`${'110101'}${b(v0, bpv)}`)] = this.global.fn; diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 4aa2984..d9228d6 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -1987,8 +1987,8 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(global.man.positions[2][1]).toEqual(EMPTY); expect(global.man.world.getDot(2,1)).toEqual(EMPTY); - global.man.positions[2][1] = EMPTY; - global.man.world.setDot(2,1,EMPTY); + global.man.positions[1][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); }); describe('pick() operator with 3bits per var', () => { @@ -2168,12 +2168,78 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(global.man.positions[2][1]).toEqual(EMPTY); expect(global.man.world.getDot(2,1)).toEqual(EMPTY); - global.man.positions[2][1] = EMPTY; - global.man.world.setDot(2,1,EMPTY); + global.man.positions[1][0] = EMPTY; + global.man.world.setDot(1,0,EMPTY); }); }); }); + describe('say() operator', () => { + it("Checking say to nothing", () => { + ops.vars[0] = 1; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org.msg).toEqual(0); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1, 0)).toEqual(EMPTY); + }); + + it("Checking say to other organism 1", () => { + const org2 = new OrganismDos(1, 1, 0, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[1][0] = EMPTY; + }); + it("Checking say to other organism 2", () => { + const org2 = new OrganismDos(1, 1, 1, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][1] = org2; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[1][1] = EMPTY; + }); + it("Checking say to other organism 3", () => { + const org2 = new OrganismDos(1, 0, 1, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[0][1] = org2; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[0][1] = EMPTY; + }); + + it("Checking say to many organisms", () => { + const org2 = new OrganismDos(1, 1, 0, {}); + const org3 = new OrganismDos(1, 1, 1, {}); + + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][0] = org2; + global.man.positions[1][1] = org3; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(org3.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[1][0] = EMPTY; + global.man.positions[1][1] = EMPTY; + }); + }); + xdescribe('onCheckLeft() method', () => { let org; let ops; From 2f40b9788bf91c30545e3d3af7b54df4e2b2ae7d Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 24 Jun 2018 23:05:05 +0300 Subject: [PATCH 77/88] added test for 'say' operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 271 +++++++++++++++++- 1 file changed, 270 insertions(+), 1 deletion(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index d9228d6..371c263 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2220,8 +2220,25 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([11, 1, 2, 3]); global.man.positions[0][1] = EMPTY; }); + it("Checking say to other organism twice", () => { + const org2 = new OrganismDos(1, 1, 0, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); - it("Checking say to many organisms", () => { + ops.vars[0] = 12; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + expect(org2.msg).toEqual(12); + expect(ops.vars).toEqual([12, 1, 2, 3]); + + global.man.positions[1][0] = EMPTY; + }); + + it("Checking say to many organisms 1", () => { const org2 = new OrganismDos(1, 1, 0, {}); const org3 = new OrganismDos(1, 1, 1, {}); @@ -2235,9 +2252,261 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(org2.msg).toEqual(11); expect(org3.msg).toEqual(11); expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[1][0] = EMPTY; global.man.positions[1][1] = EMPTY; + org2.destroy(); + org3.destroy(); + }); + it("Checking say to many organisms 2", () => { + const org2 = new OrganismDos(1, 1, 1, {}); + const org3 = new OrganismDos(1, 0, 1, {}); + + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][1] = org2; + global.man.positions[0][1] = org3; + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(org3.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[1][1] = EMPTY; + global.man.positions[0][1] = EMPTY; + org2.destroy(); + org3.destroy(); }); + it("Checking say to 8 organisms", () => { + const org1 = new OrganismDos(1, 0, 0, {}); + const org2 = new OrganismDos(1, 1, 0, {}); + const org3 = new OrganismDos(1, 2, 0, {}); + const org4 = new OrganismDos(1, 0, 1, {}); + const org5 = new OrganismDos(1, 0, 2, {}); + const org6 = new OrganismDos(1, 1, 2, {}); + const org7 = new OrganismDos(1, 2, 2, {}); + const org8 = new OrganismDos(1, 2, 1, {}); + + ops.vars[0] = 11; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = org1; + global.man.positions[1][0] = org2; + global.man.positions[2][0] = org3; + global.man.positions[0][1] = org4; + global.man.positions[0][2] = org5; + global.man.positions[1][2] = org6; + global.man.positions[2][2] = org7; + global.man.positions[2][1] = org8; + + expect(ops.operators[hex('110101 00')].call(ops, 0, hex('110101 00'), org)).toEqual(1); + + expect(org1.msg).toEqual(11); + expect(org2.msg).toEqual(11); + expect(org3.msg).toEqual(11); + expect(org4.msg).toEqual(11); + expect(org5.msg).toEqual(11); + expect(org6.msg).toEqual(11); + expect(org7.msg).toEqual(11); + expect(org8.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + global.man.positions[0][0] = EMPTY; + global.man.positions[1][0] = EMPTY; + global.man.positions[2][0] = EMPTY; + global.man.positions[0][1] = EMPTY; + global.man.positions[0][2] = EMPTY; + global.man.positions[1][2] = EMPTY; + global.man.positions[2][2] = EMPTY; + global.man.positions[2][1] = EMPTY; + + org1.destroy(); + org2.destroy(); + org3.destroy(); + org4.destroy(); + org5.destroy(); + org6.destroy(); + org7.destroy(); + org8.destroy(); + }); + + describe('say() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking say to nothing", () => { + ops.vars[0] = 1; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org.msg).toEqual(0); + expect(global.man.positions[1][0]).toEqual(EMPTY); + expect(global.man.world.getDot(1, 0)).toEqual(EMPTY); + }); + + it("Checking say to other organism 1", () => { + const org2 = new OrganismDos(1, 1, 0, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + global.man.positions[1][0] = EMPTY; + }); + it("Checking say to other organism 2", () => { + const org2 = new OrganismDos(1, 1, 1, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][1] = org2; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + global.man.positions[1][1] = EMPTY; + }); + it("Checking say to other organism 3", () => { + const org2 = new OrganismDos(1, 0, 1, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[0][1] = org2; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + global.man.positions[0][1] = EMPTY; + }); + it("Checking say to other organism twice", () => { + const org2 = new OrganismDos(1, 1, 0, {}); + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][0] = org2; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + expect(org2.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + + ops.vars[0] = 12; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + expect(org2.msg).toEqual(12); + expect(ops.vars).toEqual([12, 1, 2, 3, 4, 5, 6, 7]); + + global.man.positions[1][0] = EMPTY; + }); + + it("Checking say to many organisms 1", () => { + const org2 = new OrganismDos(1, 1, 0, {}); + const org3 = new OrganismDos(1, 1, 1, {}); + + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][0] = org2; + global.man.positions[1][1] = org3; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(org3.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + + global.man.positions[1][0] = EMPTY; + global.man.positions[1][1] = EMPTY; + org2.destroy(); + org3.destroy(); + }); + it("Checking say to many organisms 2", () => { + const org2 = new OrganismDos(1, 1, 1, {}); + const org3 = new OrganismDos(1, 0, 1, {}); + + ops.vars[0] = 11; + org.x = 0; + org.y = 0; + global.man.positions[1][1] = org2; + global.man.positions[0][1] = org3; + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org2.msg).toEqual(11); + expect(org3.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + global.man.positions[1][1] = EMPTY; + global.man.positions[0][1] = EMPTY; + org2.destroy(); + org3.destroy(); + }); + it("Checking say to 8 organisms", () => { + const org1 = new OrganismDos(1, 0, 0, {}); + const org2 = new OrganismDos(1, 1, 0, {}); + const org3 = new OrganismDos(1, 2, 0, {}); + const org4 = new OrganismDos(1, 0, 1, {}); + const org5 = new OrganismDos(1, 0, 2, {}); + const org6 = new OrganismDos(1, 1, 2, {}); + const org7 = new OrganismDos(1, 2, 2, {}); + const org8 = new OrganismDos(1, 2, 1, {}); + + ops.vars[0] = 11; + org.x = 1; + org.y = 1; + global.man.positions[0][0] = org1; + global.man.positions[1][0] = org2; + global.man.positions[2][0] = org3; + global.man.positions[0][1] = org4; + global.man.positions[0][2] = org5; + global.man.positions[1][2] = org6; + global.man.positions[2][2] = org7; + global.man.positions[2][1] = org8; + + expect(ops.operators[hex('110101 000')].call(ops, 0, hex('110101 000'), org)).toEqual(1); + + expect(org1.msg).toEqual(11); + expect(org2.msg).toEqual(11); + expect(org3.msg).toEqual(11); + expect(org4.msg).toEqual(11); + expect(org5.msg).toEqual(11); + expect(org6.msg).toEqual(11); + expect(org7.msg).toEqual(11); + expect(org8.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + global.man.positions[0][0] = EMPTY; + global.man.positions[1][0] = EMPTY; + global.man.positions[2][0] = EMPTY; + global.man.positions[0][1] = EMPTY; + global.man.positions[0][2] = EMPTY; + global.man.positions[1][2] = EMPTY; + global.man.positions[2][2] = EMPTY; + global.man.positions[2][1] = EMPTY; + + org1.destroy(); + org2.destroy(); + org3.destroy(); + org4.destroy(); + org5.destroy(); + org6.destroy(); + org7.destroy(); + org8.destroy(); + }); + }) }); xdescribe('onCheckLeft() method', () => { From 304c6e5262a2709892fa64eb5755f25e1f337319 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 24 Jun 2018 23:50:42 +0300 Subject: [PATCH 78/88] changed function call logic. from now, function will be called, if at least one function exist --- client/src/vm/Operators.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index f2e97c3..341f5fd 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -281,13 +281,12 @@ class Operators { const h = Helper.toHexNum; const ifBit = Num.MAX_BITS - 1; const fnBits = Num.MAX_BITS - this.FUNC_NAME_BITS; - const funcs = Math.pow(2, this.FUNC_NAME_BITS); const varBits = Num.MAX_BITS - OConfig.codeBitsPerVar; const opBits = Num.BITS_PER_OPERATOR; eval(`Operators.global.fn = function call(line, num, org) { const data = num << ${opBits}; - const offs = this.funcs[data >>> ${ifBit} === 0 ? Math.round(this.vars[data << 1 >>> ${varBits}]) % ${funcs} : data << 1 >>> ${fnBits}]; + const offs = this.funcs[data >>> ${ifBit} === 0 ? Math.round(this.vars[data << 1 >>> ${varBits}]) % this._funcAmount : (data << 1 >>> ${fnBits}) % this._funcAmount]; if (offs !== undefined) { if (this.stack.length > ${MAX_STACK_SIZE}) { org.energy -= org.vm.size; @@ -470,6 +469,7 @@ class Operators { this._OPERATORS_CB = Operators._compiledOperators; this.stack = []; this.funcs = new Array(this._MAX_FUNC_AMOUNT); + this._funcAmount = 0; } /** @@ -482,9 +482,9 @@ class Operators { const offs = this.offs; const funcs = this.funcs = new Array(this._MAX_FUNC_AMOUNT); const blocks = []; - let func = 0; - this.stack = []; + this._funcAmount = 0; + this.stack = []; for (let i = 0; i < len; i++) { const operator = code[i] >>> varOffs; if (operator === 0b100010 || operator === 0b100011) { // if, while @@ -494,7 +494,7 @@ class Operators { } if (operator === 0b100101) { // func offs[i] = i; - funcs[func++] = i + 1; + funcs[this._funcAmount++] = i + 1; blocks.push(i); continue; } From a6071d0cd8c5b7e976bdfc82824a44ba0915d854 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 25 Jun 2018 01:06:48 +0300 Subject: [PATCH 79/88] updated Code2JS for new myDir and funcCall operators fixed funcCall with empty body issue fixed NaN energy issue --- client/src/manager/plugins/organisms/Config.js | 12 ++++++------ .../manager/plugins/organisms/dos/Code2JS.js | 4 +++- client/src/vm/Code2JS.js | 6 +++--- client/src/vm/Operators.js | 17 ++++++++++++----- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/client/src/manager/plugins/organisms/Config.js b/client/src/manager/plugins/organisms/Config.js index cb2fd1c..903d5e9 100644 --- a/client/src/manager/plugins/organisms/Config.js +++ b/client/src/manager/plugins/organisms/Config.js @@ -27,12 +27,12 @@ const Config = { * implemented. See Operators.operators getter for details. Values may be float. */ orgOperatorWeights: [ - .0001, .0001, .0001, .0001, .0001, // var, const, if, loop, operator, - .00001, .00001, .00001, .00001, // func, funcCall, return, bracket - .0001, .0001, // toMem, fromMem, - .000001, .01, .0001, .0001, .0001, // lookAt, step, dir, myX, myY, - .01, .00001, .0001, .0001, .0001, // eat, put, energy, pick, poison, - .0001, .000001, .000001, .00001, .0001 // rand, say, listen, check, myEnergy + .0001, .0001, .0001, .0001, .0001, // var, const, if, loop, operator, + .00001, .00001, .00001, .00001, // func, funcCall, return, bracket + .0001, .0001, .0001, // toMem, fromMem, rand, + .000001, .01, .0001, .0001, .0001, // lookAt, step, dir, myX, myY, + .01, .00001, .0001, .0001, // eat, put, energy, pick, + .000001, .000001, .00001, .0001, .0001, .0001 // say, listen, check, myEnergy, myAge, myDir ], /** * {Array} Probabilities which used, when mutator decides what to do: diff --git a/client/src/manager/plugins/organisms/dos/Code2JS.js b/client/src/manager/plugins/organisms/dos/Code2JS.js index 47f5a7f..365f994 100644 --- a/client/src/manager/plugins/organisms/dos/Code2JS.js +++ b/client/src/manager/plugins/organisms/dos/Code2JS.js @@ -32,6 +32,7 @@ class Code2JS extends BaseCode2JS { this.operators[0b110111] = this._onCheck.bind(this); this.operators[0b111000] = this._onMyEnergy.bind(this); this.operators[0b111001] = this._onMyAge.bind(this); + this.operators[0b111010] = this._onMyDir.bind(this); // // API of the Manager for accessing outside. (e.g. from Console) // @@ -50,13 +51,14 @@ class Code2JS extends BaseCode2JS { _onMyY(num) {return `v${Num.getVar0(num)}=myY()`} _onEat(num) {return `eat(v${Num.getVar0(num)})`} _onPut(num) {return `put(v${Num.getVar0(num)})`} - _onEnergy(num) {return `energy()`} + _onEnergy() {return `energy()`} _onPick(num) {return `pick(v${Num.getVar0(num)})`} _onSay(num) {return `say(v${Num.getVar0(num)})`} _onListen(num) {return `v${Num.getVar0(num)}=listen()`} _onCheck(num) {return `v${Num.getVar0(num)}=check()`} _onMyEnergy(num) {return `v${Num.getVar0(num)}=myEnergy()`} _onMyAge(num) {return `v${Num.getVar0(num)}=myAge()`} + _onMyDir(num) {return `v${Num.getVar0(num)}=myDir()`} } module.exports = Code2JS; \ No newline at end of file diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index 8446797..447b6fc 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -89,7 +89,7 @@ class Code2JS { return `while(v${Num.getVar0(num)}${this._CONDITIONS[cond]}v${Num.getVar1(num)}){${bracket}`; } - _onOperator(num, line, ops) { + _onOperator(num) { return `v${Num.getVar0(num)}=v${Num.getVar1(num)}${this._CONDITIONS[Num.getBits(num, Num.BITS_OF_VAR3, Operators.CONDITION_BITS)]}v${Num.getVar2(num)}`; } @@ -102,9 +102,9 @@ class Code2JS { let fn; if (Num.getBits(num, Num.BITS_OF_VAR0, 1) === 1) { - fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, ops.FUNC_NAME_BITS)}`; + fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, ops.FUNC_NAME_BITS) % ops.funcAmount}`; } else { - fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar)}`; + fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar) % ops.funcAmount}`; } return `${fn}()`; } diff --git a/client/src/vm/Operators.js b/client/src/vm/Operators.js index 341f5fd..cc3a785 100644 --- a/client/src/vm/Operators.js +++ b/client/src/vm/Operators.js @@ -286,12 +286,19 @@ class Operators { eval(`Operators.global.fn = function call(line, num, org) { const data = num << ${opBits}; - const offs = this.funcs[data >>> ${ifBit} === 0 ? Math.round(this.vars[data << 1 >>> ${varBits}]) % this._funcAmount : (data << 1 >>> ${fnBits}) % this._funcAmount]; + const offs = this.funcs[data >>> ${ifBit} === 0 ? Math.round(this.vars[data << 1 >>> ${varBits}]) % this.funcAmount : (data << 1 >>> ${fnBits}) % this.funcAmount]; if (offs !== undefined) { + // + // Maximum amount of functions were created + // if (this.stack.length > ${MAX_STACK_SIZE}) { org.energy -= org.vm.size; return ++line; } + // + // Function has no body, so we don't need to jump into it + // + if (this.offs[offs - 1] === offs - 1) {return ++line} this.stack.push(line + 1, offs - 1, this.vars.slice()); return offs; } @@ -469,7 +476,7 @@ class Operators { this._OPERATORS_CB = Operators._compiledOperators; this.stack = []; this.funcs = new Array(this._MAX_FUNC_AMOUNT); - this._funcAmount = 0; + this.funcAmount = 0; } /** @@ -483,8 +490,8 @@ class Operators { const funcs = this.funcs = new Array(this._MAX_FUNC_AMOUNT); const blocks = []; - this._funcAmount = 0; - this.stack = []; + this.funcAmount = 0; + this.stack = []; for (let i = 0; i < len; i++) { const operator = code[i] >>> varOffs; if (operator === 0b100010 || operator === 0b100011) { // if, while @@ -494,7 +501,7 @@ class Operators { } if (operator === 0b100101) { // func offs[i] = i; - funcs[this._funcAmount++] = i + 1; + funcs[this.funcAmount++] = i + 1; blocks.push(i); continue; } From d0cf0b13f936408c1ea0c9ca43e88582b9ba82cf Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 25 Jun 2018 01:36:55 +0300 Subject: [PATCH 80/88] fixed an issue with undefined func name call --- client/src/vm/Code2JS.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index 447b6fc..e899258 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -102,9 +102,9 @@ class Code2JS { let fn; if (Num.getBits(num, Num.BITS_OF_VAR0, 1) === 1) { - fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, ops.FUNC_NAME_BITS) % ops.funcAmount}`; + fn = `f${Num.getBits(num, Num.BITS_OF_VAR0 + 1, Operators.FUNC_NAME_BITS) % (ops.funcAmount || 1)}`; } else { - fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar) % ops.funcAmount}`; + fn = `v${Num.getBits(num, Num.BITS_OF_VAR0 + 1, OConfig.codeBitsPerVar) % (ops.funcAmount || 1)}`; } return `${fn}()`; } From adb586e761be75466667e88a5b9e7febdb21e1d0 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 25 Jun 2018 22:54:52 +0300 Subject: [PATCH 81/88] added tests for listen and check operators #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index ff0ae72..7d5ef82 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2509,6 +2509,82 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }) }); + describe('listen() operator', () => { + it("Checking listen command 1", () => { + org.msg = 11; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110110 00')].call(ops, 0, hex('110110 00'), org)).toEqual(1); + expect(org.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3]); + }); + it("Checking listen command 2", () => { + org.msg = 0; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110110 01')].call(ops, 0, hex('110110 01'), org)).toEqual(1); + expect(org.msg).toEqual(0); + expect(ops.vars).toEqual([0, 0, 2, 3]); + }); + + describe('listen() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it("Checking listen command 1", () => { + org.msg = 11; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110110 000')].call(ops, 0, hex('110110 000'), org)).toEqual(1); + expect(org.msg).toEqual(11); + expect(ops.vars).toEqual([11, 1, 2, 3, 4, 5, 6, 7]); + }); + it("Checking listen command 2", () => { + org.msg = 0; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(org.msg).toEqual(0); + expect(ops.vars).toEqual([0, 0, 2, 3, 4, 5, 6, 7]); + }); + }); + }); + + describe('check() operator', () => { + it('Check out of the world ', () => { + org.dir = DIRS.UP; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, EMPTY, 2, 3]); + }); + it('Check object', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY0, 2, 3]); + global.man.positions[1][0] = EMPTY; + }); + }); + xdescribe('onCheckLeft() method', () => { let org; let ops; From 80daacbe6bd9c8eb67dbe4b2f5e003e8d79ef152 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Mon, 25 Jun 2018 23:01:29 +0300 Subject: [PATCH 82/88] added tests for check operator #145 --- .../manager/plugins/organisms/dos/OperatorsSpec.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 7d5ef82..94e5b5d 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2573,7 +2573,7 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); expect(ops.vars).toEqual([0, EMPTY, 2, 3]); }); - it('Check object', () => { + it('Check object 1', () => { org.x = 1; org.y = 1; org.dir = DIRS.UP; @@ -2583,6 +2583,16 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY0, 2, 3]); global.man.positions[1][0] = EMPTY; }); + it('Check object 2', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + global.man.positions[2][1] = OBJECT_TYPES.TYPE_ENERGY1; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY1, 2, 3]); + global.man.positions[2][1] = EMPTY; + }); }); xdescribe('onCheckLeft() method', () => { From 1203080ab00d50cc29996d47f418fbf747465399 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 26 Jun 2018 22:07:43 +0300 Subject: [PATCH 83/88] added tests for check operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 94e5b5d..c3588f4 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2593,6 +2593,180 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY1, 2, 3]); global.man.positions[2][1] = EMPTY; }); + it('Check object 3', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + global.man.positions[1][2] = OBJECT_TYPES.TYPE_ENERGY3; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY3, 2, 3]); + global.man.positions[1][2] = EMPTY; + }); + it('Check object 4', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY4; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY4, 2, 3]); + global.man.positions[0][1] = EMPTY; + }); + + it('Check energy 1', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, ENERGY, 2, 3]); + global.man.world.setDot(1,0,EMPTY); + }); + it('Check energy 2', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + global.man.world.setDot(2,1,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 01')].call(ops, 0, hex('110111 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, ENERGY, 2, 3]); + global.man.world.setDot(2,1,EMPTY); + }); + it('Check energy 3', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + global.man.world.setDot(1,2,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 11')].call(ops, 0, hex('110111 11'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, ENERGY]); + global.man.world.setDot(1,2,EMPTY); + }); + it('Check energy 4', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + global.man.world.setDot(0,1,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 00')].call(ops, 0, hex('110111 00'), org)).toEqual(1); + expect(ops.vars).toEqual([ENERGY, 1, 2, 3]); + global.man.world.setDot(0,1,EMPTY); + }); + + describe('listen() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Check out of the world ', () => { + org.dir = DIRS.UP; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, EMPTY, 2, 3, 4, 5, 6, 7]); + }); + it('Check object 1', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + global.man.positions[1][0] = OBJECT_TYPES.TYPE_ENERGY0; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY0, 2, 3, 4, 5, 6, 7]); + global.man.positions[1][0] = EMPTY; + }); + it('Check object 2', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + global.man.positions[2][1] = OBJECT_TYPES.TYPE_ENERGY1; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY1, 2, 3, 4, 5, 6, 7]); + global.man.positions[2][1] = EMPTY; + }); + it('Check object 3', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + global.man.positions[1][2] = OBJECT_TYPES.TYPE_ENERGY3; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY3, 2, 3, 4, 5, 6, 7]); + global.man.positions[1][2] = EMPTY; + }); + it('Check object 4', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + global.man.positions[0][1] = OBJECT_TYPES.TYPE_ENERGY4; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, OBJECT_TYPES.TYPE_ENERGY4, 2, 3, 4, 5, 6, 7]); + global.man.positions[0][1] = EMPTY; + }); + + it('Check energy 1', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, ENERGY, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(1,0,EMPTY); + }); + it('Check energy 2', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + global.man.world.setDot(2,1,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 001')].call(ops, 0, hex('110111 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, ENERGY, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(2,1,EMPTY); + }); + it('Check energy 3', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + global.man.world.setDot(1,2,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 011')].call(ops, 0, hex('110111 011'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, ENERGY, 4, 5, 6, 7]); + global.man.world.setDot(1,2,EMPTY); + }); + it('Check energy 4', () => { + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + global.man.world.setDot(0,1,0xaabbcc); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 000')].call(ops, 0, hex('110111 000'), org)).toEqual(1); + expect(ops.vars).toEqual([ENERGY, 1, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(0,1,EMPTY); + }); + }); }); xdescribe('onCheckLeft() method', () => { From a9f3c7812a840c77124a91e665520ed7b43043cd Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 26 Jun 2018 22:18:38 +0300 Subject: [PATCH 84/88] added tests for 'check' operator #145 --- .../plugins/organisms/dos/Operators.js | 2 +- .../plugins/organisms/dos/OperatorsSpec.js | 116 +++++++++++++++++- 2 files changed, 116 insertions(+), 2 deletions(-) diff --git a/client/src/manager/plugins/organisms/dos/Operators.js b/client/src/manager/plugins/organisms/dos/Operators.js index 814aa5e..70a4672 100644 --- a/client/src/manager/plugins/organisms/dos/Operators.js +++ b/client/src/manager/plugins/organisms/dos/Operators.js @@ -619,7 +619,7 @@ class OperatorsDos extends Operators { } /** - * Returns type of the dot under x,y coordinates + * Returns type of the dot under x,y coordinat3s * @param {Number} x X coordinate * @param {Number} y Y coordinate * @returns {Number} dot type diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index c3588f4..ea8a588 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2655,7 +2655,64 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { global.man.world.setDot(0,1,EMPTY); }); - describe('listen() operator with 3bits per var', () => { + it('Check organism 1', () => { + const org2 = new OrganismDos('0', 1, 0, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xaabbcc); + global.man.positions[1][0] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 00')].call(ops, 0, hex('110111 00'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3]); + global.man.world.setDot(1,0,EMPTY); + global.man.positions[1][0] = EMPTY; + org2.destroy(); + }); + it('Check organism 2', () => { + const org2 = new OrganismDos('0', 2, 1, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + global.man.world.setDot(2,1,0xaabbcc); + global.man.positions[2][1] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 00')].call(ops, 0, hex('110111 00'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3]); + global.man.world.setDot(2,1,EMPTY); + global.man.positions[2][1] = EMPTY; + org2.destroy(); + }); + it('Check organism 3', () => { + const org2 = new OrganismDos('0', 1, 2, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + global.man.world.setDot(1,2,0xaabbcc); + global.man.positions[1][2] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 00')].call(ops, 0, hex('110111 00'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3]); + global.man.world.setDot(1,2,EMPTY); + global.man.positions[1][2] = EMPTY; + org2.destroy(); + }); + it('Check organism 4', () => { + const org2 = new OrganismDos('0', 0, 1, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + global.man.world.setDot(0,1,0xaabbcc); + global.man.positions[0][1] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('110111 00')].call(ops, 0, hex('110111 00'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3]); + global.man.world.setDot(0,1,EMPTY); + global.man.positions[0][1] = EMPTY; + org2.destroy(); + }); + + describe('check() operator with 3bits per var', () => { let bpv; let ops; let vars; @@ -2766,6 +2823,63 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { expect(ops.vars).toEqual([ENERGY, 1, 2, 3, 4, 5, 6, 7]); global.man.world.setDot(0,1,EMPTY); }); + + it('Check organism 1', () => { + const org2 = new OrganismDos('0', 1, 0, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.UP; + global.man.world.setDot(1,0,0xaabbcc); + global.man.positions[1][0] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 000')].call(ops, 0, hex('110111 000'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(1,0,EMPTY); + global.man.positions[1][0] = EMPTY; + org2.destroy(); + }); + it('Check organism 2', () => { + const org2 = new OrganismDos('0', 2, 1, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.RIGHT; + global.man.world.setDot(2,1,0xaabbcc); + global.man.positions[2][1] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 000')].call(ops, 0, hex('110111 000'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(2,1,EMPTY); + global.man.positions[2][1] = EMPTY; + org2.destroy(); + }); + it('Check organism 3', () => { + const org2 = new OrganismDos('0', 1, 2, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.DOWN; + global.man.world.setDot(1,2,0xaabbcc); + global.man.positions[1][2] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 000')].call(ops, 0, hex('110111 000'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(1,2,EMPTY); + global.man.positions[1][2] = EMPTY; + org2.destroy(); + }); + it('Check organism 4', () => { + const org2 = new OrganismDos('0', 0, 1, {}); + org.x = 1; + org.y = 1; + org.dir = DIRS.LEFT; + global.man.world.setDot(0,1,0xaabbcc); + global.man.positions[0][1] = org2; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('110111 000')].call(ops, 0, hex('110111 000'), org)).toEqual(1); + expect(ops.vars).toEqual([ORGANISM, 1, 2, 3, 4, 5, 6, 7]); + global.man.world.setDot(0,1,EMPTY); + global.man.positions[0][1] = EMPTY; + org2.destroy(); + }); }); }); From 0a43237c65a53be2dd7605f50efeb351cf8768cd Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Tue, 26 Jun 2018 23:43:32 +0300 Subject: [PATCH 85/88] added tests for 'myEnergy' operator #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index ea8a588..14cdebb 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2883,6 +2883,59 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); + describe('myEnergy() operator', () => { + it('Check energy of organism ', () => { + org.energy = 1; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('111000 01')].call(ops, 0, hex('111000 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 3]); + }); + it('Check zero energy of organism ', () => { + org.energy = 0; + expect(ops.vars).toEqual([0, 1, 2, 3]); + expect(ops.operators[hex('111000 01')].call(ops, 0, hex('111000 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 0, 2, 3]); + }); + + describe('myEnergy() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Check energy of organism ', () => { + org.energy = 1; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('111000 001')].call(ops, 0, hex('111000 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + }); + it('Check zero energy of organism ', () => { + org.energy = 0; + expect(ops.vars).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + expect(ops.operators[hex('111000 001')].call(ops, 0, hex('111000 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 0, 2, 3, 4, 5, 6, 7]); + }); + }); + }); + xdescribe('onCheckLeft() method', () => { let org; let ops; From 7f26f739887fbda26f3162e0826b67d72d8ddd8c Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 28 Jun 2018 12:39:15 +0300 Subject: [PATCH 86/88] added tests for 'myAge' and 'myDir' operators #145 --- .../plugins/organisms/dos/OperatorsSpec.js | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js index 14cdebb..3e26f1e 100644 --- a/client/src/manager/plugins/organisms/dos/OperatorsSpec.js +++ b/client/src/manager/plugins/organisms/dos/OperatorsSpec.js @@ -2936,6 +2936,128 @@ describe("client/src/manager/plugins/organisms/dos/OperatorsDos", () => { }); }); + describe('myAge() operator', () => { + it('Check default age of organism ', () => { + expect(org.iterations).toEqual(-1); + expect(ops.operators[hex('111001 01')].call(ops, 0, hex('111001 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, -1, 2, 3]); + }); + it('Check age increase', () => { + expect(org.iterations).toEqual(-1); + expect(ops.operators[hex('111001 01')].call(ops, 0, hex('111001 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, -1, 2, 3]); + org.run(); + expect(ops.operators[hex('111001 01')].call(ops, 0, hex('111001 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 0, 2, 3]); + org.run(); + org.run(); + org.run(); + expect(ops.operators[hex('111001 01')].call(ops, 0, hex('111001 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 3, 2, 3]); + }); + + describe('myAge() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Check default age of organism ', () => { + expect(org.iterations).toEqual(-1); + expect(ops.operators[hex('111001 001')].call(ops, 0, hex('111001 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, -1, 2, 3, 4, 5, 6, 7]); + }); + it('Check age increase', () => { + expect(org.iterations).toEqual(-1); + expect(ops.operators[hex('111001 001')].call(ops, 0, hex('111001 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, -1, 2, 3, 4, 5, 6, 7]); + org.run(); + expect(ops.operators[hex('111001 001')].call(ops, 0, hex('111001 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 0, 2, 3, 4, 5, 6, 7]); + org.run(); + org.run(); + org.run(); + expect(ops.operators[hex('111001 001')].call(ops, 0, hex('111001 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 3, 2, 3, 4, 5, 6, 7]); + }); + }); + }); + + describe('myDir() operator', () => { + it('Check default direction of organism ', () => { + org.dir = DIRS.UP; + expect(ops.operators[hex('111010 11')].call(ops, 0, hex('111010 11'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 0]); + org.dir = DIRS.RIGHT; + expect(ops.operators[hex('111010 10')].call(ops, 0, hex('111010 10'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 1, 0]); + org.dir = DIRS.DOWN; + expect(ops.operators[hex('111010 01')].call(ops, 0, hex('111010 01'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 2, 1, 0]); + org.dir = DIRS.LEFT; + expect(ops.operators[hex('111010 00')].call(ops, 0, hex('111010 00'), org)).toEqual(1); + expect(ops.vars).toEqual([3, 2, 1, 0]); + }); + + describe('myDir() operator with 3bits per var', () => { + let bpv; + let ops; + let vars; + let offs; + beforeAll(() => { + bpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 3; + OperatorsDos.compile(); + }); + afterAll(() => OperatorsDos.compile()); + beforeEach(() => { + vars = [0, 1, 2, 3, 4, 5, 6, 7]; + offs = new Array(10); + ops = new OperatorsDos(offs, vars, org); + }); + afterEach(() => { + ops.destroy(); + ops = null; + offs = null; + vars = null; + OConfig.codeBitsPerVar = bpv; + }); + + it('Check default direction of organism ', () => { + org.dir = DIRS.UP; + expect(ops.operators[hex('111010 011')].call(ops, 0, hex('111010 011'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 2, 0, 4, 5, 6, 7]); + org.dir = DIRS.RIGHT; + expect(ops.operators[hex('111010 010')].call(ops, 0, hex('111010 010'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 1, 1, 0, 4, 5, 6, 7]); + org.dir = DIRS.DOWN; + expect(ops.operators[hex('111010 001')].call(ops, 0, hex('111010 001'), org)).toEqual(1); + expect(ops.vars).toEqual([0, 2, 1, 0, 4, 5, 6, 7]); + org.dir = DIRS.LEFT; + expect(ops.operators[hex('111010 000')].call(ops, 0, hex('111010 000'), org)).toEqual(1); + expect(ops.vars).toEqual([3, 2, 1, 0, 4, 5, 6, 7]); + }); + }); + }); + xdescribe('onCheckLeft() method', () => { let org; let ops; From 478427e758eab36261c790259e7fce8cb7e9b5f8 Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Thu, 28 Jun 2018 12:57:01 +0300 Subject: [PATCH 87/88] done with #127 --- README.md | 2 +- client/src/view/Canvas.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7f0dd14..40b1096 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ # 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.visualize(show:Boolean = true)` - Turns on/off visualization in browser for current instance (world). Turning visualization off, increases application speed. You may use hot key: Ctrl-V. - `man.api.toJS(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`. diff --git a/client/src/view/Canvas.js b/client/src/view/Canvas.js index 3e7ef5a..d1727e4 100644 --- a/client/src/view/Canvas.js +++ b/client/src/view/Canvas.js @@ -133,7 +133,7 @@ class Canvas extends Observer { cursor : 'pointer' })); - el.title = 'fullscreen'; + el.title = 'fullscreen (Ctrl-F)'; el.onclick = this._onFullscreen.bind(this); innerEl.onclick = this._onFullscreen.bind(this); @@ -155,7 +155,7 @@ class Canvas extends Observer { cursor : 'pointer' })); - el.title = 'visualize'; + el.title = 'visualize (Ctrl-V)'; el.onclick = this._onVisualize.bind(this); return el; From 58ebba8ce52f1ddb662c95e72d0ca503f30e78ea Mon Sep 17 00:00:00 2001 From: DeadbraiN Date: Sun, 1 Jul 2018 23:29:18 +0300 Subject: [PATCH 88/88] added tests for Code2JS class #145 --- client/src/vm/Code2JS.js | 4 ++-- client/src/vm/Code2JSSpec.js | 37 ++++++++++++++++++++++++++++++++++++ tests/jasmine.json | 3 ++- 3 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 client/src/vm/Code2JSSpec.js diff --git a/client/src/vm/Code2JS.js b/client/src/vm/Code2JS.js index e899258..44e36ab 100644 --- a/client/src/vm/Code2JS.js +++ b/client/src/vm/Code2JS.js @@ -42,7 +42,7 @@ class Code2JS { return this._operators; } - format(code, separator = '\n') { + format(code, separator = '\n', raw = false) { const len = code.length; const operators = this._operators; let jsCode = new Array(len); @@ -56,7 +56,7 @@ class Code2JS { } ops.destroy(); - return js_beautify(jsCode.join(separator), {indent_size: 4}); + return raw ? jsCode.join(separator) : js_beautify(jsCode.join(separator), {indent_size: 4}); } destroy() { diff --git a/client/src/vm/Code2JSSpec.js b/client/src/vm/Code2JSSpec.js new file mode 100644 index 0000000..5007ed2 --- /dev/null +++ b/client/src/vm/Code2JSSpec.js @@ -0,0 +1,37 @@ +const Operators = require('./Operators'); +const Code2JS = require('./Code2JS'); +const OConfig = require('./../manager/plugins/organisms/Config'); +const Helper = require('./../../../common/src/Helper'); + +describe("client/src/vm/Operators", () => { + const h = Helper.toHexNum; + let cbpv; + let ccb; + let ctjs; + let offs; + + beforeAll(() => { + cbpv = OConfig.codeBitsPerVar; + OConfig.codeBitsPerVar = 2; + ccb = OConfig.codeConstBits; + OConfig.codeConstBits = 3; + Operators.compile(); + }); + afterAll(() => { + OConfig.codeBitsPerVar = cbpv; + OConfig.codeConstBits = ccb; + }); + beforeEach(() => { + ctjs = new Code2JS(); + }); + afterEach(() => { + ctjs.destroy(); + ctjs = null; + }); + + describe('var() operator', () => { + it('Checks simplpe var assign', () => { + expect(ctjs.format([h('100000 00 01 0000000000000000000000')], '\n', true)).toEqual('v0=v1'); + }); + }); +}); \ No newline at end of file diff --git a/tests/jasmine.json b/tests/jasmine.json index 551a712..2acbb88 100644 --- a/tests/jasmine.json +++ b/tests/jasmine.json @@ -6,7 +6,8 @@ "1server/src/**/*[sS]pec.js", "1common/src/FastArraySpec.js", "1client/src/vm/OperatorsSpec.js", - "client/src/manager/plugins/organisms/dos/OperatorsSpec.js" + "1client/src/manager/plugins/organisms/dos/OperatorsSpec.js", + "client/src/vm/Code2JSSpec.js" ], "stopSpecOnExpectationFailure": false, "random": false