changed to vue

master
Ugo Finnendahl 5 years ago
parent eb13a10c3a
commit f728cc0b27
  1. 38
      index.html
  2. 1
      js/controls.js
  3. 3
      js/rl.js
  4. 208
      js/view.js

@ -3,11 +3,15 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script> <script src="https://unpkg.com/konva@4.0.0/konva.min.js"></script>
<script src='https://unpkg.com/vue/dist/vue.js'></script>
<script src='https://cdn.jsdelivr.net/npm/vue-konva@2.0.11/umd/vue-konva.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<title>RL exhibit - prototype</title> <title>RL exhibit - prototype</title>
<link rel="stylesheet" href="css/style.min.css"> <link rel="stylesheet" href="css/style.min.css">
</head> </head>
<body> <body>
<div id="container"> <div id="container" style="opacity:0">
<div id="canvas"></div> <div id="canvas"></div>
<nav> <nav>
<button class="button" onclick="machine.run(100)">run 100 episodes!</button> <button class="button" onclick="machine.run(100)">run 100 episodes!</button>
@ -15,6 +19,35 @@
<button class="button" onclick="machine.greedy_step();update_agent(machine.state, true);">greedy step!</button> <button class="button" onclick="machine.greedy_step();update_agent(machine.state, true);">greedy step!</button>
</nav> </nav>
</div> </div>
<div id="app" style="position:absolute; top:0px;">
<v-stage ref="stage" :config="stage_config">
<v-layer ref="local_layer" :config="local_layer">
<v-group ref="map_group" :config="map_config">
<!-- <v-group ref="grid_group">
<v-line v-for="y in maze.height+1" :config="get_grid_line_config(y-1, true)"></v-line>
<v-line v-for="x in maze.width+1" :config="get_grid_line_config(x-1)"></v-line>
</v-group> -->
<v-rect v-for="(t_type, idx) in maze.map.flat()" :config="get_tile_config(idx, t_type, true)"></v-rect>
<v-regular-polygon :config="get_agent_config()"></v-regular-polygon>
</v-group>
</v-layer>
<v-layer ref="map_layer">
<v-group ref="mini_map_group" :config="mini_map_config">
<!-- <v-group ref="grid_group">
<v-line v-for="y in maze.height+1" :config="get_grid_line_config(y-1, true)"></v-line>
<v-line v-for="x in maze.width+1" :config="get_grid_line_config(x-1)"></v-line>
</v-group> -->
<v-rect v-for="(t_type, idx) in maze.map.flat()" :config="get_tile_config(idx, t_type)"></v-rect>
<v-regular-polygon :config="get_agent_config()"></v-regular-polygon>
</v-group>
</v-layer>
</v-stage>
</div>
<nav>
<button class="button" onclick="machine.run(100)">run 100 episodes!</button>
<button class="button" onclick="machine.auto_step();update_agent(machine.state, true);">auto step!</button>
<button class="button" onclick="machine.greedy_step();update_agent(machine.state, true);">greedy step!</button>
</nav>
<script> <script>
var map = [ var map = [
[0, 0, 4, 2, 0, 0, 0, 0], [0, 0, 4, 2, 0, 0, 0, 0],
@ -25,7 +58,8 @@
]; ];
</script> </script>
<script src="js/rl.js"></script> <script src="js/rl.js"></script>
<script src="js/view.js"></script>
<script src="js/controls.js"></script> <script src="js/controls.js"></script>
<script src="js/view.js"></script>
</body> </body>
</html> </html>

1
js/controls.js vendored

@ -32,6 +32,7 @@ function key_callback(e) {
ret = machine.step(tmp); ret = machine.step(tmp);
} }
update_agent(machine.state, true); update_agent(machine.state, true);
// show_q_table();
} }
document.addEventListener('keydown', key_callback); document.addEventListener('keydown', key_callback);

@ -20,6 +20,7 @@ class RL_machine {
this.episode = 0; this.episode = 0;
this.epsilon = epsilon; this.epsilon = epsilon;
this.score = 0; this.score = 0;
this.running = false;
} }
reset_machine(){ reset_machine(){
this.q_table = this.q_table.map((c) => c.map((a) => a.fill(0))); this.q_table = this.q_table.map((c) => c.map((a) => a.fill(0)));
@ -58,6 +59,7 @@ class RL_machine {
return new_state; return new_state;
} }
run(episodes, max_steps_per_episode=10000){ run(episodes, max_steps_per_episode=10000){
this.running = true;
for (var i = 0; i < episodes; i++) { for (var i = 0; i < episodes; i++) {
for (var j = 0; j < max_steps_per_episode; j++) { for (var j = 0; j < max_steps_per_episode; j++) {
if (this.auto_step() != 1) { if (this.auto_step() != 1) {
@ -66,6 +68,7 @@ class RL_machine {
} }
this.new_episode(); this.new_episode();
} }
this.running = false;
} }
} }

@ -105,9 +105,7 @@ function draw_agent(state) {
break; break;
} }
if (animate){ if (animate){
console.log(fun);
this.todos.push(fun); this.todos.push(fun);
console.log(this.todos);
} else { } else {
this.todos = []; this.todos = [];
this.target_x = undefined; this.target_x = undefined;
@ -255,3 +253,209 @@ window.addEventListener('resize', function() {
draw_map(map) draw_map(map)
draw_agent(machine.state) draw_agent(machine.state)
// New
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(),
},
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;
},
destroyed() {
window.removeEventListener('resize', this.handleResize)
},
computed: {
stage_config: function () {
return {
width: this.width,
height: this.height,
}
},
mini_map_config: function () {
return {
// x: this.stage_config.width * 0.5 - (Math.round(maze.width * this.base_size)/2),
// y: this.stage_config.height * 0.5 - (Math.round(maze.height * this.base_size)/2),
x:this.width-(Math.round(maze.width * this.base_size)*0.2)-30,
y:30,
scale:{
x: 0.2,
y: 0.2
}
}
},
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
},
}
},
base_size: function () {
return Math.min(this.stage_config.height * 0.9 / this.maze.height, this.stage_config.width * 0.6 / 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_agent_config: function () {
return{
...this.agent_config,
x: this.base_size*this.state.x,
y: this.base_size*this.state.y,
}
},
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,
}
}
}
},
})

Loading…
Cancel
Save