| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- var MAKE_STORE_FUNCTION_NAME = MAKE_STORE_FUNCTION_NAME || 'makeNeuronStore'
- var DBG = DBG || false;
- var DBG1 = true;
- var DEFAULT_NEURON = {
- value: '',
- charge: 0,
- maxCharge: 1.5, // DEFAULT_CONFIG.config_max_neuron_charge,
- uiShape: "circle",
- ui: { cx: 0, cy: 0 },
- source: [],
- next: [],
- }
- function makeDefaultNeuronsStoreState() {
- return {
- receptor: [],
- mapReceptorChar: {},
- neuron: [],
- connection: [],
- doubleConn: [], // connections between two nodes
- charge: [], // TODO: list of [ { charge: number, nodeType: (receptor|neuron), nodeIdx: int }, ... ] groupd by node (type/idx)
- inputReadPos: 0,
- animPos: 0,
- doAnim: true,
- uiOutputHeight: 300,
- }
- }
- function makeNeuronStore() {
- DBG && console.log("DBG:NeuronStore:makeNeuronStore");
- var _state = makeDefaultNeuronsStoreState()
- var _config = {}
- var _inputText = ''
- var _animIntervalID = null
- var _callback = null
- function stateReset(inputText, config) {
- _inputText = inputText
- _config = config
- _state = makeDefaultNeuronsStoreState()
- var distinct = function (value, idx, self) {
- return (idx === self.indexOf(value));
- };
- var foundLetters = inputText.split("").filter(distinct);
- _state.receptor = foundLetters.sort().map(makeReceptor);
- _state.mapReceptorChar = _state.receptor.map(function (node) { return node.value; });
- if (_animIntervalID) clearInterval(_animIntervalID)
- _notifySubscribers();
- }
- function readCharFromInput() {
- if (_state.inputReadPos >= _inputText.length) return null;
- var char = _inputText.charAt(_state.inputReadPos)
- _state.inputReadPos += 1
- return char;
- }
- function forwardAnim() {
- DBG1 && console.log("DBG:NeuronStore:forwardAnim:doAnim = '" + (_state.doAnim ? 1 : 0) + "'");
- if (!_state.doAnim) return;
- // 1. read from input if its time
- // 2. check overcharged nodes
- // 2.1 check overcharged Receptor
- // 2.2 check overcharged Neuron
- // 3. move all charges (Receptor -> Connection, Connection -> Neuron, Neuron -> Connection)
- // 4. discharge all
- // ad.2. TODO: what to do with Charge when create new Neuron?
- // - idea 1: use Charge to create new Neuron: rm Charge, add Neuron, add Connection
- // 1. read from input if its time
- if (0 === _state.animPos % _config.config_read_speed_multiplier) {
- // read from input = add charge to receptor with given letter
- var char = readCharFromInput()
- if (null === char) {
- DBG1 && console.log("DBG:NeuronStore:forwardAnim:1(readInput): STOP - end of input", { inputLength: _inputText.length, animPos: _state.animPos })
- _state.doAnim = false
- _notifySubscribers()
- return;
- }
- var foundReceptorIdx = getReceptorIdx(char)
- DBG1 && console.log("DBG:NeuronStore:forwardAnim:1(readInput): char('" + char + "', [" + char.charCodeAt(0) + "])", { animPos: _state.animPos, char, len: _inputText.length, doAnim: _state.doAnim, foundReceptorIdx })
- if (-1 === foundReceptorIdx) {
- DBG1 && console.warn("BUG: receptor '" + char + "' not found (NeuronStore:forwardAnim:readInput)")
- _state.doAnim = false
- _notifySubscribers()
- return;
- }
- chargeAdd(_config.config_charge_receptor_at_input, { type: 'receptor', idx: foundReceptorIdx })
- _state.animPos += 1
- _notifySubscribers()
- return;
- }
- // 2. check overcharged nodes
- // 2.1 check overcharged Neuron
- // 2.1.1 is overcharged Neuron
- // 2.1.1.1 is another Neuron with Charge
- // 2.1.1.2 ! another Neuron with Charge
- // 2.1.2 ! overcharged Neuron
- // 2.2 check overcharged Receptor
- { // check overcharged nodes
- var overchargedNeuronIdx = _state.neuron.reduce(function (ret, neuron, idx) {
- var charge = getNeuronCharge(idx)
- if (charge < neuron.maxCharge) return ret;
- ret.push({ idx: idx, charge: charge })
- return ret;
- }, [])
- var overchargedReceptorIdx = _state.receptor.reduce(function (ret, receptor, idx) {
- var charge = getReceptorCharge(idx)
- if (charge < _config.config_max_receptor_charge) return ret;
- ret.push({ idx: idx, charge: charge })
- return ret;
- }, [])
- if (overchargedNeuronIdx.length > 0) {
- var overcharged = overchargedNeuronIdx[0]
- var firstNeuron = _state.neuron[overcharged.idx]
- var secondNeuronWithCharge = _state.neuron.reduce(function (ret, neuron, idx) { // find neuron with max charge
- if (idx === overcharged.idx) return ret; // skip firstNeuron
- var charge = getNeuronCharge(idx)
- if (!charge) return ret; // skip Neuron without charge
- if (null === ret) return { idx: idx, charge: charge }
- return (charge > ret.charge) ? { idx: idx, charge: charge } : ret;
- }, null)
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:2.1(check overcharged)/neuron.1", { overcharged, firstNeuron, secondNeuronWithCharge })
- if (null !== secondNeuronWithCharge) {
- // is already exists - check doubleConn: { from: [ neuronIdx, neuronIdx ], to: neuronIdx }
- var existingConn = _state.doubleConn.reduce(function (ret, dblConn) {
- if (ret) return ret;
- if (dblConn.from[0] === overcharged.idx && dblConn.from[1] === secondNeuronWithCharge.idx) return dblConn;
- // if (dblConn.from[1] === overcharged.idx && dblConn.from[0] === secondNeuronWithCharge.idx) return dblConn;
- return ret;
- }, null)
- var toNode = _state.neuron[secondNeuronWithCharge.idx]
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:2.1(check overcharged)/neuron.2(secondNeuronWithCharge)", { from: firstNeuron.value, to: toNode.value, existingConn })
- if (existingConn) { // charge Neuron existingConn.to
- var idxNewNeuron = existingConn.to
- chargeRemove({ type: 'neuron', idx: overcharged.idx })
- chargeRemove({ type: 'neuron', idx: secondNeuronWithCharge.idx })
- switch (_config.config_strategy_overcharge) {
- case "REMOVE_CHARGE": break;
- case "LEAVE_HALF_CHARGE": {
- chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx })
- chargeAdd(secondNeuronWithCharge.charge / 2, { type: 'neuron', idx: secondNeuronWithCharge.idx })
- } break;
- case "LEAVE_ALMOST_MAX": {
- chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx })
- chargeAdd(getNeuronAlmostMaxCharge(secondNeuronWithCharge.idx), { type: 'neuron', idx: secondNeuronWithCharge.idx })
- } break;
- }
- chargeAdd(overcharged.charge + secondNeuronWithCharge.charge, { type: 'neuron', idx: existingConn.to })
- // _state.animPos += 1
- // dischargeAll()
- _notifySubscribers()
- return;
- } else { // create new
- var newNeuron = makeNeuronFromTwoNeurons(overcharged.idx, overcharged.charge, secondNeuronWithCharge.idx, secondNeuronWithCharge.charge)
- if (!newNeuron) {
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/neuron.2.1(!newNeuron)", { overcharged })
- // _state.animPos += 1
- dischargeAll()
- _notifySubscribers()
- return;
- } else {
- _state.neuron.push(newNeuron)
- updateOuputHeight(newNeuron)
- var idxNewNeuron = _state.neuron.length - 1
- _state.connection.push({ fromType: 'neuron', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 })
- _state.connection.push({ fromType: 'neuron', fromIdx: secondNeuronWithCharge.idx, toIdx: idxNewNeuron, timesCreated: 1 })
- _state.doubleConn.push({ from: [overcharged.idx, secondNeuronWithCharge.idx], to: idxNewNeuron, connIdx: [_state.connection.length - 2, _state.connection.length - 1] })
- chargeRemove({ type: 'neuron', idx: overcharged.idx })
- chargeRemove({ type: 'neuron', idx: secondNeuronWithCharge.idx })
- switch (_config.config_strategy_overcharge) {
- case "REMOVE_CHARGE": break;
- case "LEAVE_HALF_CHARGE": {
- chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx })
- chargeAdd(secondNeuronWithCharge.charge / 2, { type: 'neuron', idx: secondNeuronWithCharge.idx })
- } break;
- case "LEAVE_ALMOST_MAX": {
- // chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx })
- // chargeAdd(getNeuronAlmostMaxCharge(secondNeuronWithCharge.idx), { type: 'neuron', idx: secondNeuronWithCharge.idx })
- var fromCharge = getNeuronAlmostMaxCharge(overcharged.idx)
- var toCharge = getNeuronAlmostMaxCharge(secondNeuronWithCharge.idx)
- chargeAdd((fromCharge + toCharge) / 2, { type: 'dbl_conn', idx: _state.doubleConn.length - 1, fromCharge: fromCharge, toCharge: toCharge })
- } break;
- }
- // _state.animPos += 1
- // dischargeAll()
- _notifySubscribers()
- return;
- }
- }
- // // _state.animPos += 1
- // // dischargeAll()
- // _notifySubscribers()
- // return;
- } else { // !secondNeuronWithCharge
- // TODO: check if already exists! if yes then charge else create new
- var idxFoundConnection = _state.connection.reduce(function (ret, conn, idx) {
- if (ret > -1) return ret;
- if (conn.fromType === 'neuron' && conn.fromIdx === overcharged.idx) return idx;
- return ret;
- }, -1)
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/neuron.2(!secondNeuronWithCharge)", { idxFoundConnection })
- if (-1 === idxFoundConnection) {
- var newNeuron = makeNeuronFromOneNeuron(overcharged.idx, overcharged.charge)
- if (!newNeuron) {
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/neuron.2.1(!newNeuron)", { overcharged })
- // _state.animPos += 1
- dischargeAll()
- _notifySubscribers()
- return;
- } else {
- _state.neuron.push(newNeuron)
- updateOuputHeight(newNeuron)
- var idxNewNeuron = _state.neuron.length - 1
- _state.connection.push({ fromType: 'neuron', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 })
- chargeRemove({ type: 'neuron', idx: overcharged.idx })
- switch (_config.config_strategy_overcharge) {
- case "REMOVE_CHARGE": break;
- case "LEAVE_HALF_CHARGE": {
- chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx })
- } break;
- case "LEAVE_ALMOST_MAX": {
- chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx })
- } break;
- }
- _notifySubscribers()
- return;
- }
- } else {
- _state.connection[idxFoundConnection].timesCreated += 1
- // chargeMove(overcharged.charge, { type: 'receptor', idx: overcharged.idx }, { type: 'connection', idx: idxFoundConnection })
- chargeRemove({ type: 'neuron', idx: overcharged.idx })
- switch (_config.config_strategy_overcharge) {
- case "REMOVE_CHARGE": break;
- case "LEAVE_HALF_CHARGE": {
- chargeAdd(overcharged.charge / 2, { type: 'neuron', idx: overcharged.idx })
- } break;
- case "LEAVE_ALMOST_MAX": {
- chargeAdd(getNeuronAlmostMaxCharge(overcharged.idx), { type: 'neuron', idx: overcharged.idx })
- } break;
- }
- chargeAdd(overcharged.charge, { type: 'connection', idx: idxFoundConnection })
- }
- _notifySubscribers()
- return;
- }
- // _notifySubscribers()
- // return;
- }
- if (overchargedReceptorIdx.length > 0) { // TODO: while ?
- if (1 === overchargedReceptorIdx.length) {
- var overcharged = overchargedReceptorIdx.shift()
- // Restriction: only one connection between nodes
- {
- var idxFoundConnection = _state.connection.reduce(function (ret, conn, idx) {
- if (ret > -1) return ret;
- if (conn.fromType === 'receptor' && conn.fromIdx === overcharged.idx) return idx;
- return ret;
- }, -1)
- DBG1 && console.log("DBG:NeuronStore:forwardAnim:2(check overcharged)/receptor", { idxFoundConnection, from: { type: 'receptor', idx: overcharged.idx }, conn: [].concat(_state.connection) })
- if (-1 === idxFoundConnection) {
- var newNeuron = makeNeuronFromOneReceptor(overcharged.idx, overcharged.charge)
- _state.neuron.push(newNeuron)
- var idxNewNeuron = _state.neuron.length - 1
- _state.connection.push({ fromType: 'receptor', fromIdx: overcharged.idx, toIdx: idxNewNeuron, timesCreated: 1 })
- idxFoundConnection = _state.connection.length - 1
- chargeRemove({ type: 'receptor', idx: overcharged.idx })
- // switch (_config.config_strategy_overcharge) {
- // case "REMOVE_CHARGE": break;
- // case "LEAVE_HALF_CHARGE": {
- // chargeAdd(overcharged.charge / 2, { type: 'receptor', idx: overcharged.idx })
- // } break;
- // case "LEAVE_ALMOST_MAX": {
- // chargeAdd(getReceptorAlmostMaxCharge(overcharged.idx), { type: 'receptor', idx: overcharged.idx })
- // } break;
- // }
- chargeAdd(overcharged.charge, { type: 'connection', idx: idxFoundConnection })
- } else {
- _state.connection[idxFoundConnection].timesCreated += 1
- // chargeMove(overcharged.charge, { type: 'receptor', idx: overcharged.idx }, { type: 'connection', idx: idxFoundConnection })
- chargeRemove({ type: 'receptor', idx: overcharged.idx })
- // switch (_config.config_strategy_overcharge) {
- // case "REMOVE_CHARGE": break;
- // case "LEAVE_HALF_CHARGE": {
- // chargeAdd(overcharged.charge / 2, { type: 'receptor', idx: overcharged.idx })
- // } break;
- // case "LEAVE_ALMOST_MAX": {
- // chargeAdd(getReceptorAlmostMaxCharge(overcharged.idx), { type: 'receptor', idx: overcharged.idx })
- // } break;
- // }
- chargeAdd(overcharged.charge, { type: 'connection', idx: idxFoundConnection })
- }
- }
- // _state.animPos += 1
- // dischargeAll()
- _notifySubscribers()
- return;
- } else {
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:2(check overcharged)/receptor", { TODO: "more then 1 receptor overcharged!" })
- }
- }
- // DBG1 && console.log("DBG:NeuronStore:forwardAnim:2(check overcharged)", { overchargedNeuronIdx, overchargedReceptorIdx })
- }
- { // 3. move all charges (Receptor -> Connection, Connection -> Neuron, Neuron -> Connection)
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:3(move all charges)", { charge: [].concat(_state.charge) })
- var isChargeTypeConnection = function (charge) {
- if ("connection" === charge.nodeType) return true;
- if ("dbl_conn" === charge.nodeType) return true;
- return false;
- }
- var toAddChargeNeuronIdxList = _state.charge.filter(isChargeTypeConnection).map(function (charge) {
- DBG1 && console.log("TODO:NeuronStore:forwardAnim:3(move all charges).LOOP", { charge })
- switch (charge.nodeType) {
- case "connection": return { charge: charge.charge, toIdx: _state.connection[charge.nodeIdx].toIdx };
- case "dbl_conn": return { charge: charge.charge, toIdx: _state.doubleConn[charge.nodeIdx].to };
- }
- return null;
- })
- _state.charge = _state.charge.filter(function (charge) { return !isChargeTypeConnection(charge); })
- toAddChargeNeuronIdxList.forEach(function (toAddCharge) {
- chargeAdd(toAddCharge.charge, { type: 'neuron', idx: toAddCharge.toIdx })
- })
- }
- { // 4. discharge all
- dischargeAll()
- }
- _state.animPos += 1
- _notifySubscribers();
- }
- function dischargeAll() {
- _state.charge = _state.charge.map(function (charge) {
- return Object.assign({}, charge, {
- charge: Math.max(0, charge.charge - _config.config_discharge_per_tick),
- })
- }).filter(function (charge) {
- return charge.charge > 0;
- })
- }
- function makeNeuronFromTwoNeurons(fromNeuronIdx, fromNeuronCharge, toNeuronIdx, toNeuronCharge) {
- var fromNode = _state.neuron[fromNeuronIdx]
- var toNode = _state.neuron[toNeuronIdx]
- var maxCharge = getNewNeuronMaxCharge(fromNode)
- DBG1 && console.log("DBG:NeuronStore:makeNeuronFromTwoNeurons", { fromNode, toNode, maxCharge })
- if (maxCharge < _config.config_discharge_per_tick) return null;
- var uiNewNodePos = { cx: 0, cy: 0 }
- { // closer to node with more charge (first)
- var xDiff = Math.abs(fromNode.ui.cx - toNode.ui.cx)
- var isFirstOnRight = (fromNode.ui.cx > toNode.ui.cx)
- // fromNeuronCharge + toNeuronCharge -- xDiff
- // toNeuronCharge -- x ==> x = toNeuronCharge * xDiff / (fromNeuronCharge + toNeuronCharge)
- var xToFirst = (toNeuronCharge * xDiff) / (fromNeuronCharge + toNeuronCharge)
- uiNewNodePos.cx = fromNode.ui.cx + (isFirstOnRight ? -1 : 1) * xToFirst
- }
- uiNewNodePos.cy = (fromNode.ui.cy != toNode.ui.cy)
- ? Math.max(fromNode.ui.cy, toNode.ui.cy) + 10 + _config.ui_space_y / 2
- : fromNode.ui.cy + 10 + _config.ui_space_y
- ;
- uiNewNodePos.cy = _state.neuron.reduce(function (ret, neuron) {
- if (uiNewNodePos.cx < neuron.ui.cx - 10) return ret;
- if (uiNewNodePos.cx > neuron.ui.cx + 10) return ret;
- if (ret < neuron.ui.cy - 10) return ret;
- if (ret > neuron.ui.cy + 10) return ret;
- return ret + 10 + _config.ui_space_y;
- }, uiNewNodePos.cy)
- DBG1 && console.log("DBG:NeuronStore:makeNeuronFromTwoNeurons", { uiNewNodePos, fromNode, toNode, newNodeMaxCharge: getNewNeuronMaxCharge(fromNode) })
- // var value = '' + (_state.neuron.length + 1);
- var value = [fromNode.value, toNode.value].join('')
- return Object.assign({}, DEFAULT_NEURON, {
- value: value,
- charge: 0,
- maxCharge: getNewNeuronMaxCharge(fromNode),
- uiShape: "ellipse",
- ui: Object.assign({}, uiNewNodePos, {
- rx: 10,
- ry: 10,
- }),
- });
- }
- function makeNeuronFromOneReceptor(fromReceptorIdx, charge) {
- var sourceNode = _state.receptor[fromReceptorIdx]
- // var value = '' + (_state.neuron.length + 1);
- var value = [sourceNode.value, ""].join('') // TODO: same name what Receptor
- DBG1 && console.log("DBG:NeuronStore:makeNeuronFromOneReceptor", { sourceNode, newNodeMaxCharge: getNewNeuronMaxCharge(sourceNode) })
- return Object.assign({}, DEFAULT_NEURON, {
- value: value,
- charge: 0,
- maxCharge: getNewNeuronMaxCharge(sourceNode),
- uiShape: "ellipse",
- ui: {
- cx: sourceNode.ui.cx,
- cy: sourceNode.ui.cy + 10 + _config.ui_space_y,
- rx: 10,
- ry: 10,
- },
- });
- }
- function makeNeuronFromOneNeuron(fromNeuronIdx, charge) {
- var sourceNode = _state.neuron[fromNeuronIdx]
- // var value = '' + (_state.neuron.length + 1);
- var value = [sourceNode.value, "^"].join('')
- var maxCharge = getNewNeuronMaxCharge(sourceNode)
- if (maxCharge < _config.config_discharge_per_tick) return null;
- DBG1 && console.log("DBG:NeuronStore:makeNeuronFromOneNeuron", { sourceNode, newNodeMaxCharge: maxCharge })
- return Object.assign({}, DEFAULT_NEURON, {
- value: value,
- charge: 0,
- maxCharge: maxCharge,
- uiShape: "ellipse",
- ui: {
- cx: sourceNode.ui.cx,
- cy: sourceNode.ui.cy + 10 + _config.ui_space_y,
- rx: 10,
- ry: 10,
- },
- });
- }
- function getNewNeuronMaxCharge(sourceNode) {
- // return sourceNode.maxCharge * _config.config_discharge_max_in_new_neuron_from_one;
- return sourceNode.maxCharge - _config.config_discharge_per_tick;
- }
- function chargeAdd(charge, to) {
- var foundChargeIdx = _state.charge.reduce(function (ret, charge, idx) {
- if (charge.nodeType === to.type && charge.nodeIdx === to.idx) return idx;
- return ret;
- }, -1)
- DBG1 && console.log("DBG:NeuronStore:chargeAdd", { charge, to, foundChargeIdx })
- if (-1 === foundChargeIdx) {
- _state.charge.push({ charge: charge, nodeType: to.type, nodeIdx: to.idx })
- foundChargeIdx = _state.charge.length - 1
- } else {
- _state.charge[foundChargeIdx].charge += charge
- }
- if ('dbl_conn' === to.type) {
- if (!_state.charge[foundChargeIdx].hasOwnProperty('fromCharge')) _state.charge[foundChargeIdx].fromCharge = 0
- if (!_state.charge[foundChargeIdx].hasOwnProperty('toCharge')) _state.charge[foundChargeIdx].toCharge = 0
- _state.charge[foundChargeIdx].fromCharge += to.fromCharge
- _state.charge[foundChargeIdx].toCharge += to.toCharge
- }
- DBG1 && console.log("DBG:NeuronStore:chargeAdd.2", { state_charge: [].concat(_state.charge) })
- return foundChargeIdx;
- }
- function chargeRemove(from) {
- _state.charge = _state.charge.filter(function (item) {
- return !(from.type === item.nodeType && from.idx === item.nodeIdx);
- })
- }
- function updateOuputHeight(newNeuron) {
- if (newNeuron.ui.cy + 30 > _state.uiOutputHeight) {
- _state.uiOutputHeight = newNeuron.ui.cy + 30
- }
- }
- function dispatch(payload) {
- DBG1 && console.log("DBG:NeuronStore:dispatch('" + payload.type + "')", payload);
- switch (payload.type) {
- case 'INIT': stateReset(payload.inputText, payload.config); startAnimation(); break;
- case 'PAUSE': _state.doAnim = false; _notifySubscribers(); break;
- case 'PLAY': _state.doAnim = true; break;
- default: {
- DBG1 && console.warn("Not implemented dispatch action type '" + payload.type + "'")
- }
- }
- }
- function subscribe(callback) {
- _callback = callback; // TODO: array
- return unsubscribe;
- }
- function unsubscribe() {
- _callback = null
- }
- function _notifySubscribers() {
- if (_callback) _callback()
- }
- function makeReceptor(value, idx, arr) { // usage: [].map(makeReceptor)
- var totalReceptors = arr.length;
- var cx = Math.ceil(_config.ui_output_width / (totalReceptors + 1));
- var r = Math.min(Math.ceil(_config.ui_output_width / (totalReceptors + 10) / 2), _config.ui_max_receptor_r);
- var xCenter = cx + cx * idx - r;
- return Object.assign({}, DEFAULT_NEURON, {
- value: value,
- maxCharge: _config.config_max_receptor_charge,
- uiShape: "circle",
- ui: {
- cx: xCenter,
- cy: 40,
- r: r,
- },
- next: [],
- })
- }
- function getReceptorIdx(char) {
- return _state.mapReceptorChar.indexOf(char)
- }
- function startAnimation() {
- _state.doAnim = true
- if (_animIntervalID) clearInterval(_animIntervalID)
- _animIntervalID = setInterval(forwardAnim, _config.config_anim_speed)
- }
- function getReceptorCharge(idx) {
- return _state.charge.filter(function (charge) {
- return ('receptor' === charge.nodeType && idx === charge.nodeIdx);
- }).reduce(function (ret, charge) {
- return ret + charge.charge;
- }, 0)
- }
- function getNeuronCharge(idx) {
- return _state.charge.filter(function (charge) {
- return ('neuron' === charge.nodeType && idx === charge.nodeIdx);
- }).reduce(function (ret, charge) {
- return ret + charge.charge;
- }, 0)
- }
- function getReceptorAlmostMaxCharge(idx) {
- return _state.receptor[idx].maxCharge - _config.config_discharge_per_tick;
- }
- function getNeuronAlmostMaxCharge(idx) {
- DBG1 && console.log("DBG:getNeuronAlmostMaxCharge(" + idx + ")", { charge: _state.neuron[idx].maxCharge - _config.config_discharge_per_tick })
- return _state.neuron[idx].maxCharge - _config.config_discharge_per_tick;
- }
- function getNodesChargeState() {
- var receptor = [].concat(_state.receptor);
- var neuron = [].concat(_state.neuron);
- _state.charge.forEach(function (charge) {
- // _state.charge: [ { charge: number, nodeType: (receptor|neuron), nodeIdx: int }, ... ] groupd by node (type/idx)
- switch (charge.nodeType) {
- case 'receptor': receptor[charge.nodeIdx].charge = charge.charge; break;
- case 'neuron': neuron[charge.nodeIdx].charge = charge.charge; break;
- }
- })
- function getNodeInfoFunction(type) {
- return function _getNodeInfo(node) {
- return {
- type: type,
- value: node.value,
- charge: node.charge,
- }
- }
- }
- return receptor.map(getNodeInfoFunction('receptor'))
- .concat(
- neuron.map(getNodeInfoFunction('neuron'))
- )
- ;
- }
- return {
- subscribe: subscribe,
- dispatch: dispatch,
- getState: function () { return _state; },
- getNodesChargeState: getNodesChargeState,
- getListReceptor: function () { return _state.receptor; },
- getListNeuron: function () { return _state.neuron; },
- getReceptor: function (idx) { return _state.receptor[idx]; },
- getNeuron: function (idx) { return _state.neuron[idx]; },
- getConnection: function (idx) { return _state.connection[idx]; },
- getDoubleConnection: function (idx) { return _state.doubleConn[idx]; },
- getCharge: function (idx) { return _state.charge[idx]; },
- getListConnection: function () { return _state.connection; },
- getListCharge: function () { return _state.charge; },
- getReceptorCharge: getReceptorCharge,
- getNeuronCharge: getNeuronCharge,
- }
- }
- global[MAKE_STORE_FUNCTION_NAME] = makeNeuronStore
- // export default makeNeuronStore
|