This commit is contained in:
Anton Vakhrushev 2018-05-21 08:12:29 +03:00
commit 0d4e25dbf8
14 changed files with 12923 additions and 0 deletions

4
.babelrc Normal file
View File

@ -0,0 +1,4 @@
{
"presets": ["env"],
"plugins": ["transform-class-properties"]
}

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.idea/
coverage/
dist/
node_modules/
var/

12582
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

41
package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest",
"build": "webpack",
"start:dev": "webpack-dev-server",
"format": "prettier --tab-width=4 --single-quote --trailing-comma es5 --write '{source,tests}/**/*.js'"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel": "^6.23.0",
"babel-jest": "^22.4.4",
"babel-loader": "^7.1.4",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.6.1",
"bable-loader": "0.0.1-security",
"css-loader": "^0.28.11",
"jest": "^22.4.4",
"prettier": "^1.12.1",
"sass-loader": "^7.0.1",
"style-loader": "^0.21.0",
"vue": "^2.5.16",
"webpack": "^4.8.1",
"webpack-cli": "^2.1.3",
"webpack-dev-server": "^3.1.4"
},
"jest": {
"collectCoverage": true,
"collectCoverageFrom": [
"**/source/*.js"
],
"testMatch": [
"**/tests/**/*.js"
]
}
}

61
source/Daemon.js Normal file
View File

@ -0,0 +1,61 @@
const DEFAULT_EPSILON = 0.01;
function create_key(steps) {
return steps.join('');
}
export default class Daemon {
humanCount;
robotCount;
epsilon;
weights = {};
constructor(humanCount, robotCount, epsilon = DEFAULT_EPSILON) {
this.humanCount = humanCount;
this.robotCount = robotCount;
this.epsilon = epsilon;
}
predict(movements) {
const steps = this._getStepSlice(movements);
const w0 = this._getWeight([...steps, 0]);
const w1 = this._getWeight([...steps, 1]);
if (w1 > w0) {
return 1;
} else {
return 0;
}
}
adjust(movements, humanValue, stepNumber) {
const steps = this._getStepSlice(movements);
const weightAdjustment = this._getWeightAdjustment(stepNumber);
this._adjustWeight([...steps, humanValue], weightAdjustment);
}
_getStepSlice(movements) {
return movements.getLastMovements(this.humanCount, this.robotCount);
}
_getWeightAdjustment(stepNumber) {
return Math.pow(1 + this.epsilon, stepNumber);
}
_getWeight(steps) {
const key = create_key(steps);
const weight = this.weights[key];
return weight === undefined ? 0 : weight;
}
_setWeight(steps, value) {
const key = create_key(steps);
this.weights[key] = value;
}
_adjustWeight(steps, weight) {
const currentWeight = this._getWeight(steps);
const newWeight = currentWeight + weight;
this._setWeight(steps, newWeight);
}
}

23
source/Movements.js Normal file
View File

@ -0,0 +1,23 @@
export default class Movements {
humanMovements = [];
robotMovements = [];
constructor(human = [], robot = []) {
this.humanMovements = human;
this.robotMovements = robot;
}
makeHumanMove(value) {
this.humanMovements.push(value === 1 ? value : 0);
}
makeRobotMove(value) {
this.robotMovements.push(value === 1 ? value : 0);
}
getLastMovements(humanCount, robotCount) {
const humanSlice = this.humanMovements.slice(-humanCount);
const robotSlice = this.robotMovements.slice(-robotCount);
return [].concat(robotSlice, humanSlice);
}
}

13
source/Predictor.js Normal file
View File

@ -0,0 +1,13 @@
import Movements from './Movements';
import Supervisor from './Supervisor';
export default class Predictor {
movements;
supervisor;
score = 0;
constructor() {
this.movements = new Movements();
this.supervisor = new Supervisor();
}
}

12
source/Supervisor.js Normal file
View File

@ -0,0 +1,12 @@
export default class Supervisor {
daemons = [];
constructor(daemons) {
this.daemons = daemons;
}
predict(movements) {
}
}

15
source/index.js Normal file
View File

@ -0,0 +1,15 @@
import Vue from 'vue';
import './style.css';
import Predictor from './Predictor';
new Vue({
el: '#app',
data: {
predictor: new Predictor(),
},
methods: {
pass(value) {
console.log('PASS', value);
},
},
});

20
source/style.css Normal file
View File

@ -0,0 +1,20 @@
html, body {
width: 100vw;
}
.app {
display: block;
margin: 0 auto;
width: 200px;
text-align: center;
}
.score {
font-size: 300%;
margin: 2em auto 0.8em;
display: inline-block;
}
button {
display: inline-block;
}

54
tests/DaemonTest.js Normal file
View File

@ -0,0 +1,54 @@
import Daemon from '../source/Daemon';
import expect from 'expect';
import Movements from '../source/Movements';
test('Get prediction for beginning', function() {
const m = new Movements();
const d = new Daemon(1, 1);
expect(d.predict(m)).toEqual(0);
});
test('Daemon 1-1', function() {
const m = new Movements();
const d = new Daemon(1, 1);
const step_slice = s => {
return [].concat(
s.slice(-1).slice.map(i => i.robot),
s.slice(-1).slice.map(i => i.human)
);
};
const steps = [
{
robot: 0,
human: 1,
},
{
robot: 0,
human: 1,
},
{
robot: 1,
human: 1,
},
{
robot: 0,
human: 1,
},
{
robot: 1,
human: 1,
},
];
steps.forEach((step, index) => {
const robot = d.predict(m);
// expect(d._getStepSlice(m)).toEqual(step_slice(steps));
expect(robot).toEqual(step.robot);
d.adjust(m, step.human, index + 1);
m.makeHumanMove(step.human);
m.makeRobotMove(step.robot);
console.log('Step', index + 1, d);
});
});

38
tests/MovementsTest.js Normal file
View File

@ -0,0 +1,38 @@
import Movements from '../source/Movements';
import expect from 'expect';
test('Create with empty constructor', function() {
const m = new Movements();
expect(m.getLastMovements(5, 5)).toEqual([]);
});
test('Constructor with human steps', function() {
const m = new Movements([1, 1]);
expect(m.getLastMovements(5, 5)).toEqual([1, 1]);
});
test('Make human step', function() {
const m = new Movements();
m.makeHumanMove(1);
m.makeHumanMove(0);
expect(m.getLastMovements(5, 5)).toEqual([1, 0]);
});
test('Make robot step', function() {
const m = new Movements();
m.makeRobotMove(0);
m.makeRobotMove(1);
expect(m.getLastMovements(5, 5)).toEqual([0, 1]);
});
test('Make mixed steps', function() {
const m = new Movements();
m.makeHumanMove(1);
m.makeRobotMove(0);
expect(m.getLastMovements(5, 5)).toEqual([0, 1]);
});
test('Get slice', function() {
const m = new Movements([1, 0, 0, 1], [1, 1, 0, 0]);
expect(m.getLastMovements(2, 2)).toEqual([0, 0, 0, 1]);
});

19
tools/npm Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
mkdir -p var/docker-cache/.npm
docker run \
--rm \
--interactive \
--tty \
--init \
--user "$UID:$(id -g)" \
--volume $PWD:/srv/app \
--volume $HOME:$HOME \
--volume $PWD/var/docker-cache/.npm:/tmp/.npm \
--expose=9000 \
--publish=9000:9000 \
--env npm_config_cache=/tmp/.npm \
--workdir /srv/app \
node:10 \
npm "$@"

36
webpack.config.js Normal file
View File

@ -0,0 +1,36 @@
const path = require('path');
module.exports = {
mode: 'development',
entry: path.resolve(__dirname, 'source/index.js'),
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
contentBase: path.resolve(__dirname, 'dist'),
host: "0.0.0.0",
port: 9000,
}
};