Код гадалки Шеннона перенесен в проект
This commit is contained in:
parent
c6200a3d74
commit
f585b103c1
32
npm-shrinkwrap.json
generated
32
npm-shrinkwrap.json
generated
@ -776,6 +776,12 @@
|
||||
"integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-syntax-class-properties": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
|
||||
"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-syntax-exponentiation-operator": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
|
||||
@ -799,6 +805,18 @@
|
||||
"babel-runtime": "^6.22.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-class-properties": {
|
||||
"version": "6.24.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
|
||||
"integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-helper-function-name": "^6.24.1",
|
||||
"babel-plugin-syntax-class-properties": "^6.8.0",
|
||||
"babel-runtime": "^6.22.0",
|
||||
"babel-template": "^6.24.1"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-es2015-arrow-functions": {
|
||||
"version": "6.22.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
|
||||
@ -1053,6 +1071,15 @@
|
||||
"regenerator-transform": "^0.10.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-runtime": {
|
||||
"version": "6.23.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
|
||||
"integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "^6.22.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-transform-strict-mode": {
|
||||
"version": "6.24.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
|
||||
@ -6654,11 +6681,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"predictor": {
|
||||
"version": "git+https://github.com/anwinged/predictor.git#c7636b74d4a710b6874e703cd2a2d430c6aedf2e",
|
||||
"from": "git+https://github.com/anwinged/predictor.git",
|
||||
"dev": true
|
||||
},
|
||||
"prepend-http": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||
|
@ -8,13 +8,14 @@
|
||||
"autoprefixer": "^8.6.5",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-runtime": "^6.23.0",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"css-loader": "^0.28.11",
|
||||
"glob": "^7.1.3",
|
||||
"mini-css-extract-plugin": "^0.4.5",
|
||||
"node-sass": "^4.11.0",
|
||||
"postcss-loader": "^2.1.6",
|
||||
"predictor": "git+https://github.com/anwinged/predictor.git",
|
||||
"prettier": "^1.16.4",
|
||||
"sass-loader": "^7.1.0",
|
||||
"style-loader": "^0.21.0",
|
||||
|
@ -9,7 +9,7 @@ keywords: [php, serialization]
|
||||
В PHP есть две функции для сериализации и десериализации данных: `serialize()` и `unserialize()`.
|
||||
Функции встроены в язык, не требуют дополнительных модулей.
|
||||
|
||||
В один момент кто-то решает использовать их для долговременного хранения объектов.
|
||||
В один момент кто-то решает использовать их для долговременного хранения объектов.
|
||||
В базе данных, на диске, еще где-то.
|
||||
|
||||
```
|
||||
@ -38,5 +38,5 @@ O:16:"Test\Serialize\A":0:{}O:16:"Test\Serialize\A":0:{}
|
||||
|
||||
Не делайте так.
|
||||
|
||||
Контролируйте процесс сериализации. Например используйте JSON и специальные
|
||||
Контролируйте процесс сериализации. Например используйте JSON и специальные
|
||||
функции для превращения объекта в массив и обратно.
|
||||
|
145
source/_assets/predictor/Daemon.js
Normal file
145
source/_assets/predictor/Daemon.js
Normal file
@ -0,0 +1,145 @@
|
||||
const DEFAULT_EPSILON = 0.01;
|
||||
|
||||
/**
|
||||
* @param {Number[]} steps
|
||||
*
|
||||
* @returns {String}
|
||||
*/
|
||||
function create_key(steps) {
|
||||
return steps.join(':');
|
||||
}
|
||||
|
||||
class Daemon {
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
base;
|
||||
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
humanCount;
|
||||
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
robotCount;
|
||||
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
epsilon;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
*/
|
||||
weights = {};
|
||||
|
||||
/**
|
||||
* @param {Number} base
|
||||
* @param {Number} humanCount
|
||||
* @param {Number} robotCount
|
||||
* @param {Number} epsilon
|
||||
*/
|
||||
constructor(base, humanCount, robotCount, epsilon = DEFAULT_EPSILON) {
|
||||
this.base = base;
|
||||
this.humanCount = humanCount;
|
||||
this.robotCount = robotCount;
|
||||
this.epsilon = epsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Number}
|
||||
*/
|
||||
get power() {
|
||||
return this.humanCount + this.robotCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Journal} journal
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
predict(journal) {
|
||||
const steps = this._getStepSlice(journal);
|
||||
|
||||
const proposals = [];
|
||||
for (let i = 0; i < this.base; ++i) {
|
||||
proposals[i] = this._getWeight([...steps, i]);
|
||||
}
|
||||
|
||||
const maxWeight = Math.max(...proposals);
|
||||
|
||||
return proposals.indexOf(maxWeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Journal} journal
|
||||
* @param {Number} humanValue
|
||||
*/
|
||||
adjust(journal, humanValue) {
|
||||
const steps = this._getStepSlice(journal);
|
||||
const adjustmentWeight = this._getAdjustmentWeight(journal.length);
|
||||
this._adjustWeight([...steps, humanValue], adjustmentWeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Journal} journal
|
||||
*
|
||||
* @returns {Number[]}
|
||||
*/
|
||||
_getStepSlice(journal) {
|
||||
return journal.getLastMovements(this.humanCount, this.robotCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} stepNumber
|
||||
*
|
||||
* @returns {Number}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_getAdjustmentWeight(stepNumber) {
|
||||
return Math.pow(1 + this.epsilon, stepNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number[]} steps
|
||||
*
|
||||
* @returns {Number}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_getWeight(steps) {
|
||||
const key = create_key(steps);
|
||||
const weight = this.weights[key];
|
||||
return weight === undefined ? 0 : weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number[]} steps
|
||||
* @param {Number} value
|
||||
*
|
||||
* @returns {Number}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_setWeight(steps, value) {
|
||||
const key = create_key(steps);
|
||||
this.weights[key] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number[]} steps
|
||||
* @param {Number} weight
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_adjustWeight(steps, weight) {
|
||||
const currentWeight = this._getWeight(steps);
|
||||
const newWeight = currentWeight + weight;
|
||||
this._setWeight(steps, newWeight);
|
||||
}
|
||||
}
|
||||
|
||||
export default Daemon;
|
47
source/_assets/predictor/Journal.js
Normal file
47
source/_assets/predictor/Journal.js
Normal file
@ -0,0 +1,47 @@
|
||||
import Move from './Move';
|
||||
|
||||
class Journal {
|
||||
/**
|
||||
* @type {Move[]}
|
||||
*/
|
||||
moves = [];
|
||||
|
||||
/**
|
||||
* @param {Move[]} moves
|
||||
*/
|
||||
constructor(moves = []) {
|
||||
this.moves = moves;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} human
|
||||
* @param {Number} robot
|
||||
*/
|
||||
makeMove(human, robot) {
|
||||
this.moves.push(new Move(human, robot));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} humanCount
|
||||
* @param {Number} robotCount
|
||||
*
|
||||
* @returns {Number[]}
|
||||
*/
|
||||
getLastMovements(humanCount, robotCount) {
|
||||
const humanMoves = this.moves.map(m => m.human);
|
||||
const robotMoves = this.moves.map(m => m.robot);
|
||||
return [].concat(
|
||||
robotMoves.slice(-robotCount),
|
||||
humanMoves.slice(-humanCount)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Number}
|
||||
*/
|
||||
get length() {
|
||||
return this.moves.length;
|
||||
}
|
||||
}
|
||||
|
||||
export default Journal;
|
15
source/_assets/predictor/Move.js
Normal file
15
source/_assets/predictor/Move.js
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Represents one game move.
|
||||
*/
|
||||
class Move {
|
||||
/**
|
||||
* @param {Number} human
|
||||
* @param {Number} robot
|
||||
*/
|
||||
constructor(human, robot) {
|
||||
this.human = human;
|
||||
this.robot = robot;
|
||||
}
|
||||
}
|
||||
|
||||
export default Move;
|
90
source/_assets/predictor/Predictor.js
Normal file
90
source/_assets/predictor/Predictor.js
Normal file
@ -0,0 +1,90 @@
|
||||
import Daemon from './Daemon';
|
||||
import Journal from './Journal';
|
||||
import Supervisor from './Supervisor';
|
||||
|
||||
const DEFAULT_CONFIG = {
|
||||
base: 2,
|
||||
supervisor_epsilon: 0.01,
|
||||
daemons: [
|
||||
{ human: 2, robot: 2, epsilon: 0.01 },
|
||||
{ human: 3, robot: 3, epsilon: 0.01 },
|
||||
{ human: 4, robot: 4, epsilon: 0.01 },
|
||||
{ human: 5, robot: 5, epsilon: 0.01 },
|
||||
{ human: 6, robot: 6, epsilon: 0.01 },
|
||||
],
|
||||
};
|
||||
|
||||
export default class Predictor {
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
base;
|
||||
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
score;
|
||||
|
||||
/**
|
||||
* @type {Journal}
|
||||
*/
|
||||
journal;
|
||||
|
||||
/**
|
||||
* @type {Supervisor}
|
||||
*/
|
||||
supervisor;
|
||||
|
||||
/**
|
||||
* @param {Object} config
|
||||
*/
|
||||
constructor(config = DEFAULT_CONFIG) {
|
||||
this.base = config.base;
|
||||
this.score = 0;
|
||||
this.journal = new Journal();
|
||||
const daemons = this._createDaemons(config.daemons);
|
||||
this.supervisor = new Supervisor(daemons, config.supervisor_epsilon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number|String} humanValue
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
pass(humanValue) {
|
||||
const value = parseInt(humanValue, 10);
|
||||
if (value < 0 || value >= this.base) {
|
||||
throw new Error(`Passed value must be in [0, ${this.base})`);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} daemonConfigs
|
||||
*
|
||||
* @returns {Daemon[]}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_createDaemons(daemonConfigs) {
|
||||
return daemonConfigs.map(config => {
|
||||
return new Daemon(
|
||||
this.base,
|
||||
config.human,
|
||||
config.robot,
|
||||
config.epsilon || 0.01
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Number}
|
||||
*/
|
||||
stepCount() {
|
||||
return this.journal.length;
|
||||
}
|
||||
}
|
102
source/_assets/predictor/Supervisor.js
Normal file
102
source/_assets/predictor/Supervisor.js
Normal file
@ -0,0 +1,102 @@
|
||||
const DEFAULT_EPSILON = 0.01;
|
||||
|
||||
class Supervisor {
|
||||
/**
|
||||
* @type {{daemon: Daemon, rate: Number}[]}
|
||||
*/
|
||||
daemons = [];
|
||||
|
||||
/**
|
||||
* @type {Number}
|
||||
*/
|
||||
epsilon;
|
||||
|
||||
/**
|
||||
* @param {Daemon[]} daemons
|
||||
* @param {Number} epsilon
|
||||
*/
|
||||
constructor(daemons, epsilon = DEFAULT_EPSILON) {
|
||||
if (!daemons || daemons.length === 0) {
|
||||
throw Error('Empty daemon list');
|
||||
}
|
||||
this.daemons = daemons.map(daemon => ({
|
||||
daemon: daemon,
|
||||
rate: 0,
|
||||
}));
|
||||
this.epsilon = epsilon;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Journal} journal
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
predict(journal) {
|
||||
const predictions = this._createPredictions(journal);
|
||||
const ordered = this._sortPredictions(predictions);
|
||||
|
||||
return ordered[0].value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Journal} journal
|
||||
* @param {Number} humanValue
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Journal} journal
|
||||
*
|
||||
* @returns {Array}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_createPredictions(journal) {
|
||||
return this.daemons.map(daemon => ({
|
||||
daemon: daemon,
|
||||
power: daemon.daemon.power,
|
||||
rate: daemon.rate,
|
||||
value: daemon.daemon.predict(journal),
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} predictions
|
||||
*
|
||||
* @returns {Array}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_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;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} stepNumber
|
||||
*
|
||||
* @returns {Number}
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_getAdjustmentWeight(stepNumber) {
|
||||
return Math.pow(1 + this.epsilon, stepNumber);
|
||||
}
|
||||
}
|
||||
|
||||
export default Supervisor;
|
@ -39,7 +39,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Predictor from 'predictor';
|
||||
import Predictor from './Predictor';
|
||||
import Metrika from '../common/metrika';
|
||||
|
||||
const PREDICTOR_GAME_END_GOAL = 'PREDICTOR_GAME_END';
|
||||
|
@ -47,6 +47,7 @@ module.exports = (env = {}) => {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['babel-preset-env'],
|
||||
plugins: ['transform-class-properties'],
|
||||
},
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user