Vue.component('line-chart', { extends: VueChartJs.Line, mixins: [VueChartJs.mixins.reactiveProp], props: ['options'], // mixins: [VueChartJs.mixins.reactiveData], // props: ['options','labels', 'datasets'], // watch: { // 'labels': function(new_val) { // this.chartData = { // 'labels': new_val, // 'datasets': this.datasets}; // }, // 'datasets': { // deep:true, // handler: function(new_val) { // this.chartData = { // 'labels': this.labels, // 'datasets': new_val}; // } // } // }, mounted () { this.renderChart(this.chartData, this.options); }, }) Array.prototype.simpleSMA=function(N) { return this.map( function(el,index, _arr) { return _arr.filter( function(x2,i2) { return i2 <= index && i2 > index - N; }) .reduce( function(last, current,index, arr){ return (current/arr.length + last); },0); }); }; Array.prototype.max=function() { return this.map( function(el,index, _arr) { return _arr.filter( function(x2,i2) { return i2 <= index; }) .reduce( function(last, current){ return last > current ? last:current; },-1000000000); }); }; app = new Vue({ el: '#app', data: { width: 0, height: 0, q_table: machine.q_table, maze: maze, state: {x:0,y:0}, state_tween: new TimelineLite(), score: machine.score, score_history: machine.score_history, labels: [], }, created() { // Resize handler window.addEventListener('resize', this.handleResize) this.handleResize(); // State wrapper var s = machine.state; var $this = this; this.state = this.s2p(s); Object.defineProperty(machine, 'state', { get: function() { return this._state }, set: function(ne) { this._state=ne; $this.handleState(this._state); } }); machine.state = s; // Score wrapper var s = machine.score; var $this = this; this.score = s; Object.defineProperty(machine, 'score', { get: function() { return this._score }, set: function(ne) { this._score=ne; $this.score=ne} }); machine.score = s; // Score history wrapper var s = machine.score_history; var $this = this; this.score_history = s; Object.defineProperty(machine, 'score_history', { get: function() { return this._score_history }, set: function(ne) { this._score_history=ne; $this.score_history=ne} }); machine.score_history = s; }, destroyed() { window.removeEventListener('resize', this.handleResize) }, computed: { datacollection: function () { return { labels: Array.from(Array(this.score_history.length).keys()), datasets: [ { label: 'Data One', backgroundColor: 'rgb(0,0,0,0)', data: this.score_history.simpleSMA(Math.round(50)), fill: false, borderColor: 'rgb(255, 159, 64)', pointRadius: 1, }, { label: 'Data One', backgroundColor: 'rgb(0,0,0,0)', data: this.score_history.max(), fill: false, borderColor: 'rgb(64, 159, 255)', pointRadius: 1, }, ] } }, stage_config: function () { return { width: this.width, height: this.height, } }, mini_map_config: function () { return { x:this.width/2-(this.base_size*(this.maze.width)/2), y:this.height/2-(this.base_size*(this.maze.height)/2), scale:{ x: 1, y: 1 } } }, local_layer: function () { return { x: this.width/2, y: this.height/2, scale:{ x: 2, y: 2 } } }, map_config: function () { return { x: this.base_size*(this.maze.width-this.state.x), y: this.base_size*(this.maze.height-this.state.y), offset: { x: this.base_size*this.maze.width+this.base_size/2, y: this.base_size*this.maze.height+this.base_size/2, } } }, agent_config: function () { return { sides: 5, radius: this.base_size / 3, fill: '#00D2FF', stroke: 'black', strokeWidth: this.strokeW, offset: { x: -this.base_size / 2, y: -this.base_size / 2 }, x: this.base_size*this.state.x, y: this.base_size*this.state.y, } }, base_size: function () { return Math.min(this.stage_config.height * 0.8 / this.maze.height, this.stage_config.width * 0.5 / this.maze.width); }, strokeW: function () { return this.base_size / 50; }, }, methods: { s2p: function(state){ return { x: (state%this.maze.width), y: Math.floor(state/this.maze.width), } }, p2s: function(x,y){ return x+y*this.maze.width; }, handleResize: function() { this.width = window.innerWidth; this.height = window.innerHeight; }, handleState: function(s) { if (!machine.running){ this.state_tween.to(this.state, 0.2, { x: this.s2p(s).x, y: this.s2p(s).y }); } else { this.state = this.s2p(s); } // this.hidden_state = s; }, get_grid_line_config: function (idx, y=false) { var offset = this.strokeW/2; if (y){ var points = [-offset, Math.round(idx * this.base_size), this.base_size * this.maze.width + offset,Math.round(idx * this.base_size)]; } else { var points = [Math.round(idx * this.base_size), -offset, Math.round(idx * this.base_size), this.base_size * this.maze.height + offset]; } return { points: points, stroke: '#ddd', strokeWidth: this.strokeW, } }, get_tile_type: function (state){ var pos = this.s2p(state); if (pos.y > maze.height){ return null; } else if (pos.x > maze.width){ return null; } else { return maze.map[pos.y][pos.x]; } }, in_plus: function (pos1, pos2) { if (Math.abs(pos1.x-pos2.x) + Math.abs(pos1.y-pos2.y) < 2) { return true; } return false; }, get_tile_config: function (i, t_type, local=false) { var pos = this.s2p(i); var over = {}; // not in plus if (local) { if (!this.in_plus(this.s2p(i),{x:Math.round(this.state.x),y:Math.round(this.state.y)})) { over = { opacity: 0, fill: "#eee" }; } else if (i != this.p2s(Math.round(this.state.x),Math.round(this.state.y))) { over = { opacity: 1, fill: "#eee" }; } } const layout = { x: this.base_size * pos.x, y: this.base_size * pos.y, width: this.base_size, height: this.base_size, stroke: '#ddd', strokeWidth: this.strokeW, }; switch (t_type) { case tile.regular: return { ...layout, fill: '#fff', opacity: 1, ...over, } case tile.end: return { ...layout, fill: '#0eb500', opacity: 1, ...over, } case tile.start: return { ...layout, fill: '#ff0008', opacity: 1, ...over, } case tile.dangerous: return { ...layout, fill: '#FF7B17', opacity: 1, ...over, } } } }, })