diff --git a/source/Daemon.js b/source/Daemon.js index 8dd53a9..a8b766e 100644 --- a/source/Daemon.js +++ b/source/Daemon.js @@ -16,29 +16,29 @@ export default class Daemon { this.epsilon = epsilon; } + get power() { + return this.humanCount + this.robotCount; + } + predict(journal) { const steps = this._getStepSlice(journal); const w0 = this._getWeight([...steps, 0]); const w1 = this._getWeight([...steps, 1]); - if (w1 > w0) { - return 1; - } else { - return 0; - } + return w1 > w0 ? 1 : 0; } - adjust(movements, humanValue, stepNumber) { - const steps = this._getStepSlice(movements); - const weightAdjustment = this._getWeightAdjustment(stepNumber); - this._adjustWeight([...steps, humanValue], weightAdjustment); + adjust(journal, humanValue) { + const steps = this._getStepSlice(journal); + const adjustmentWeight = this._getAdjustmentWeight(journal.length); + this._adjustWeight([...steps, humanValue], adjustmentWeight); } - _getStepSlice(movements) { - return movements.getLastMovements(this.humanCount, this.robotCount); + _getStepSlice(journal) { + return journal.getLastMovements(this.humanCount, this.robotCount); } - _getWeightAdjustment(stepNumber) { + _getAdjustmentWeight(stepNumber) { return Math.pow(1 + this.epsilon, stepNumber); } @@ -51,6 +51,7 @@ export default class Daemon { _setWeight(steps, value) { const key = create_key(steps); this.weights[key] = value; + console.log('WEIGHTS', this.weights); } _adjustWeight(steps, weight) { diff --git a/source/Journal.js b/source/Journal.js index c0af542..350fe08 100644 --- a/source/Journal.js +++ b/source/Journal.js @@ -19,4 +19,8 @@ export default class Journal { humanMoves.slice(-humanCount) ); } + + get length() { + return this.moves.length; + } } diff --git a/source/Predictor.js b/source/Predictor.js index 96ab941..6ac738b 100644 --- a/source/Predictor.js +++ b/source/Predictor.js @@ -1,13 +1,23 @@ -import History from './Journal'; +import Journal from './Journal'; import Supervisor from './Supervisor'; +import Daemon from './Daemon'; export default class Predictor { - movements; + score; + journal; supervisor; - score = 0; constructor() { - this.movements = new History(); - this.supervisor = new Supervisor(); + this.score = 0; + this.journal = new Journal(); + this.supervisor = new Supervisor([new Daemon(3, 3)]); + } + + pass(value) { + const prediction = this.supervisor.predict(this.journal); + this.score += prediction === value ? -1 : 1; + this.supervisor.adjust(this.journal, value); + this.journal.makeMove(value, prediction); + return prediction; } } diff --git a/source/Supervisor.js b/source/Supervisor.js index fd6c3fd..b787592 100644 --- a/source/Supervisor.js +++ b/source/Supervisor.js @@ -1,9 +1,61 @@ +const DEFAULT_EPSILON = 0.01; + export default class Supervisor { daemons = []; + epsilon; - constructor(daemons) { - this.daemons = daemons; + constructor(daemons, epsilon = DEFAULT_EPSILON) { + if (!daemons) { + throw Error('Empty daemon list'); + } + this.daemons = daemons.map(daemon => ({ + daemon: daemon, + rate: 0, + })); + this.epsilon = epsilon; } - predict(movements) {} + predict(journal) { + const predictions = this._createPredictions(journal); + const ordered = this._sortPredictions(predictions); + + console.log(ordered); + + return ordered[0].value; + } + + adjust(journal, humanValue) { + const predictions = this._createPredictions(journal); + for (const prediction of predictions) { + if (prediction.value === humanValue) { + prediction.daemon.rate += this._getAdjustmentWeight( + journal.length + ); + } + prediction.daemon.daemon.adjust(journal, humanValue); + } + } + + _createPredictions(journal) { + return this.daemons.map(daemon => ({ + daemon: daemon, + power: daemon.daemon.power, + rate: daemon.rate, + value: daemon.daemon.predict(journal), + })); + } + + _sortPredictions(predictions) { + return predictions.sort((result1, result2) => { + const rateDiff = result2.rate - result1.rate; + if (Math.abs(rateDiff) > 0.000001) { + return rateDiff; + } + return result1.power - result2.power; + }); + } + + _getAdjustmentWeight(stepNumber) { + return Math.pow(1 + this.epsilon, stepNumber); + } } diff --git a/source/index.js b/source/index.js index a3c6221..1ba6f4b 100644 --- a/source/index.js +++ b/source/index.js @@ -1,6 +1,6 @@ import Vue from 'vue'; -import Predictor from './Predictor'; import './style.css'; +import Predictor from './Predictor'; new Vue({ el: '#app', @@ -8,8 +8,17 @@ new Vue({ predictor: new Predictor(), }, methods: { + click(v) { + const value = v ? 1 : 0; + this.pass(value); + }, + press(evt) { + const value = evt.key === '1' ? 0 : 1; + this.pass(value); + }, pass(value) { - console.log('PASS', value); + const prediction = this.predictor.pass(value); + console.log('PREDICTED', prediction, 'PASS', value); }, }, }); diff --git a/tests/DaemonTest.js b/tests/DaemonTest.js index d872e88..0dc8ba7 100644 --- a/tests/DaemonTest.js +++ b/tests/DaemonTest.js @@ -8,6 +8,11 @@ test('Get prediction for beginning', function() { expect(d.predict(m)).toEqual(0); }); +test('Can get power', function() { + const d = new Daemon(5, 8); + expect(d.power).toEqual(13); +}); + test('Daemon 1-1', function() { const m = new History(); const d = new Daemon(1, 1); diff --git a/web/index.html b/web/index.html index 7834480..8b1bdf8 100644 --- a/web/index.html +++ b/web/index.html @@ -1,18 +1,18 @@ - Hello + Predictor -
+
{{ predictor.score }}
- - + +
- + \ No newline at end of file