mirror of
https://github.com/wassname/rl_2d_walker.js.git
synced 2026-09-09 11:33:20 +08:00
rename and strip index
This commit is contained in:
@@ -1,127 +0,0 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML5 Genetic Algorithm Biped Walkers</title>
|
||||
<link rel="stylesheet" href="css/walkers.css" type="text/css" />
|
||||
<script src="js/jsbox2d.js"></script>
|
||||
<script src="js/walker.js"></script>
|
||||
<script src="js/game.js"></script>
|
||||
<script src="js/floor.js"></script>
|
||||
<script src="js/draw.js"></script>
|
||||
<script src="js/interface.js"></script>
|
||||
<script>
|
||||
|
||||
function init() {
|
||||
gameInit();
|
||||
}
|
||||
|
||||
window.addEventListener("load", init, false);
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="main_holder">
|
||||
<h1>Genetic Algorithm Walkers</h1>
|
||||
<h3 id="page_quote">"It's like watching other people QWOP"</h3>
|
||||
<canvas id="main_screen" width="800" height="350"></canvas>
|
||||
<div id="generation_timer"><div id="generation_timer_bar"> </div></div>
|
||||
|
||||
<div id="info">
|
||||
|
||||
<div>
|
||||
<h2>Current Generation (<span id="gen_number">0</span>)</h2>
|
||||
<table class="name_list_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="name_list">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Record History</h2>
|
||||
<table class="name_list_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Gen</th>
|
||||
<th>Name</th>
|
||||
<th>Score</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="champ_list">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="controls">
|
||||
<h2>Controls</h2>
|
||||
Gene mutation probability
|
||||
<select id="mutation_chance">
|
||||
<option value="0">0%</option>
|
||||
<option value="0.01">1%</option>
|
||||
<option value="0.05">5%</option>
|
||||
<option value="0.1">10%</option>
|
||||
<option value="0.25">25%</option>
|
||||
<option value="0.5">50%</option>
|
||||
<option value="0.75">75%</option>
|
||||
<option value="1">100%</option>
|
||||
</select><br />
|
||||
Gene mutation amount
|
||||
<select id="mutation_amount">
|
||||
<option value="0">0%</option>
|
||||
<option value="0.01">1%</option>
|
||||
<option value="0.05">5%</option>
|
||||
<option value="0.1">10%</option>
|
||||
<option value="0.25">25%</option>
|
||||
<option value="0.5">50%</option>
|
||||
<option value="0.75">75%</option>
|
||||
<option value="1">100%</option>
|
||||
</select><br />
|
||||
Champions to copy
|
||||
<select id="elite_clones"></select><br />
|
||||
Motor noise
|
||||
<select id="motor_noise">
|
||||
<option value="0">0%</option>
|
||||
<option value="0.01">1%</option>
|
||||
<option value="0.02">2%</option>
|
||||
<option value="0.03">3%</option>
|
||||
<option value="0.04">4%</option>
|
||||
<option value="0.05">5%</option>
|
||||
<option value="0.1">10%</option>
|
||||
</select><br />
|
||||
Round length
|
||||
<select id="round_length">
|
||||
<option value="300">Very short</option>
|
||||
<option value="600">Short</option>
|
||||
<option value="1200">Regular</option>
|
||||
<option value="1800">Long</option>
|
||||
<option value="2400">Looooong</option>
|
||||
</select><br />
|
||||
Animation quality
|
||||
<select id="draw_fps">
|
||||
<option value="0">none</option>
|
||||
<option value="10">10 fps</option>
|
||||
<option value="30">30 fps</option>
|
||||
<option value="60">60 fps</option>
|
||||
</select><br />
|
||||
Simulation speed
|
||||
<select id="simulation_fps">
|
||||
<option value="0">Pause</option>
|
||||
<option value="30">30</option>
|
||||
<option value="60">60</option>
|
||||
<option value="120">120</option>
|
||||
<option value="1000">1000</option>
|
||||
</select><br />
|
||||
<br />
|
||||
Lower the animation quality and simulation speed to save some CPU.<br /><br />
|
||||
Zero frames per second and high simulation speed will give you the fastest results, but processor usage will go up as well.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>HTML5 Genetic Algorithm Biped Walkers</title>
|
||||
<link rel="stylesheet" href="css/walkers.css" type="text/css" />
|
||||
<script src="vendor/jsbox2d.js"></script>
|
||||
<script src="vendor/neurojs-v2.js"></script>
|
||||
<script src="js/walker.js"></script>
|
||||
<script src="js/game.js"></script>
|
||||
<script src="js/floor.js"></script>
|
||||
<script src="js/draw.js"></script>
|
||||
<script src="js/agent.js"></script>
|
||||
<script>
|
||||
|
||||
function init() {
|
||||
gameInit();
|
||||
}
|
||||
|
||||
window.addEventListener("load", init, false);
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="main_holder">
|
||||
<h1>Genetic Algorithm Walkers</h1>
|
||||
<h3 id="page_quote">"It's like watching other people QWOP"</h3>
|
||||
<canvas id="main_screen" width="800" height="350"></canvas>
|
||||
<div id="generation_timer"><div id="generation_timer_bar"> </div></div>
|
||||
|
||||
<div id="info"></div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
|
||||
function Agent(opt, world) {
|
||||
this.walker = new Walker(world.world)
|
||||
this.options = opt
|
||||
|
||||
this.world = world
|
||||
this.frequency = 20
|
||||
this.reward = 0
|
||||
this.loaded = false
|
||||
|
||||
this.loss = 0
|
||||
this.timer = 0
|
||||
this.timerFrequency = 60 / this.frequency
|
||||
this.resetFrequency = 30 / this.frequency
|
||||
|
||||
if (this.options.dynamicallyLoaded !== true) {
|
||||
this.init(world.brains.actor.newConfiguration(), null)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Agent.prototype.init = function (actor, critic) {
|
||||
var actions = this.walker.joints.length
|
||||
var temporal = 1
|
||||
var states = this.walker.bodies.length * 2
|
||||
|
||||
var input = window.neurojs.Agent.getInputDimension(states, actions, temporal)
|
||||
|
||||
this.brain = new window.neurojs.Agent({
|
||||
|
||||
actor: actor,
|
||||
critic: critic,
|
||||
|
||||
states: states,
|
||||
actions: actions,
|
||||
|
||||
algorithm: 'ddpg',
|
||||
|
||||
temporalWindow: temporal,
|
||||
|
||||
discount: 0.97,
|
||||
|
||||
experience: 75e3,
|
||||
// buffer: window.neurojs.Buffers.UniformReplayBuffer,
|
||||
|
||||
learningPerTick: 40,
|
||||
startLearningAt: 900,
|
||||
|
||||
theta: 0.05, // progressive copy
|
||||
|
||||
alpha: 0.1 // advantage learning
|
||||
|
||||
})
|
||||
|
||||
// this.world.brains.shared.add('actor', this.brain.algorithm.actor)
|
||||
this.world.brains.shared.add('critic', this.brain.algorithm.critic)
|
||||
|
||||
this.actions = actions
|
||||
this.loaded = true
|
||||
};
|
||||
|
||||
Agent.prototype.step = function () {
|
||||
if (!this.loaded) {
|
||||
return
|
||||
}
|
||||
|
||||
this.timer++
|
||||
|
||||
if (this.timer % this.timerFrequency === 0) {
|
||||
|
||||
// reward from last step
|
||||
this.reward = this.walker.score * 1
|
||||
// console.log(this.reward)
|
||||
this.walker.score = 0
|
||||
|
||||
// train
|
||||
this.loss = this.brain.learn(this.reward)
|
||||
this.action = this.brain.policy(this.walker.getState())
|
||||
}
|
||||
|
||||
if (this.action) {
|
||||
this.walker.simulationStep(this.action)
|
||||
}
|
||||
|
||||
return this.timer % this.timerFrequency === 0
|
||||
};
|
||||
+5
-13
@@ -51,18 +51,10 @@ drawFloor = function() {
|
||||
globals.ctx.stroke();
|
||||
}
|
||||
|
||||
drawWalker = function(walker) {
|
||||
if(walker.is_elite) {
|
||||
//globals.ctx.strokeStyle = "hsl(22,"+100*walker.health/config.walker_health+"%,35%)";
|
||||
// globals.ctx.fillStyle = "hsl(20,"+45*walker.health/config.walker_health+"%,85%)";
|
||||
globals.ctx.strokeStyle = "hsl(22,100%,"+(90-55*walker.health/config.walker_health)+"%)";
|
||||
globals.ctx.fillStyle = "hsl(20,45%,"+(100-15*walker.health/config.walker_health)+"%)";
|
||||
} else {
|
||||
//globals.ctx.strokeStyle = "hsl(240,"+100*walker.health/config.walker_health+"%,41%)";
|
||||
// globals.ctx.fillStyle = "hsl(240,"+17*walker.health/config.walker_health+"%,85%)";
|
||||
globals.ctx.strokeStyle = "hsl(240,100%,"+(90-49*walker.health/config.walker_health)+"%)";
|
||||
globals.ctx.fillStyle = "hsl(240,45%,"+(100-15*walker.health/config.walker_health)+"%)";
|
||||
}
|
||||
drawWalker = function (walker) {
|
||||
var hue = walker.hue || 240
|
||||
globals.ctx.strokeStyle = "hsl("+hue+",100%,"+(90-49*walker.health/config.walker_health)+"%)";
|
||||
globals.ctx.fillStyle = "hsl("+hue+",45%,"+(100-15*walker.health/config.walker_health)+"%)";
|
||||
globals.ctx.lineWidth = 1/globals.zoom;
|
||||
|
||||
// left legs and arms first
|
||||
@@ -141,4 +133,4 @@ getZoom = function(min_x, max_x, min_y, max_y) {
|
||||
var delta_y = Math.abs(max_y - min_y);
|
||||
var zoom = Math.min(globals.main_screen.width/delta_x,globals.main_screen.height/delta_y);
|
||||
return zoom;
|
||||
}
|
||||
}
|
||||
|
||||
+79
-169
@@ -7,7 +7,7 @@ config = {
|
||||
max_zoom_factor: 130,
|
||||
min_motor_speed: -2,
|
||||
max_motor_speed: 2,
|
||||
population_size: 20,
|
||||
population_size: 4,
|
||||
mutation_chance: 0.1,
|
||||
mutation_amount: 0.5,
|
||||
walker_health: 300,
|
||||
@@ -16,7 +16,7 @@ config = {
|
||||
elite_clones: 2,
|
||||
max_floor_tiles: 50,
|
||||
round_length: 1200,
|
||||
min_body_delta: 1.4,
|
||||
min_body_delta: 0,
|
||||
min_leg_delta: 0.4,
|
||||
instadeath_delta: 0.4
|
||||
};
|
||||
@@ -24,17 +24,60 @@ config = {
|
||||
globals = {};
|
||||
|
||||
gameInit = function() {
|
||||
interfaceSetup();
|
||||
var joints = 12
|
||||
var bodyParts = 14
|
||||
var sensors = 14
|
||||
var state = sensors * 2
|
||||
var actions = joints
|
||||
var input = 2 * state + 1 * actions
|
||||
|
||||
globals.brains = {
|
||||
actor: new window.neurojs.Network.Model([
|
||||
{ type: 'input', size: input },
|
||||
{ type: 'fc', size: 60, activation: 'relu' },
|
||||
{ type: 'fc', size: 40, activation: 'relu', dropout: 0.30 },
|
||||
{ type: 'fc', size: actions, activation: 'tanh' },
|
||||
{ type: 'regression' }
|
||||
|
||||
]),
|
||||
|
||||
critic: new window.neurojs.Network.Model([
|
||||
|
||||
{ type: 'input', size: input + actions },
|
||||
{ type: 'fc', size: 80, activation: 'relu' },
|
||||
{ type: 'fc', size: 70, activation: 'relu' },
|
||||
{ type: 'fc', size: 60, activation: 'relu' },
|
||||
{ type: 'fc', size: 50, activation: 'relu' },
|
||||
{ type: 'fc', size: 1 },
|
||||
{ type: 'regression' }
|
||||
|
||||
])
|
||||
|
||||
}
|
||||
|
||||
globals.brains.shared = new window.neurojs.Shared.ConfigPool()
|
||||
|
||||
// this.brains.shared.set('actor', this.brains.actor.newConfiguration())
|
||||
globals.brains.shared.set('critic', globals.brains.critic.newConfiguration())
|
||||
|
||||
|
||||
globals.world = new b2.World(new b2.Vec2(0, -10));
|
||||
globals.walkers = createPopulation();
|
||||
[globals.agents, globals.walkers] = createPopulation();
|
||||
|
||||
globals.floor = createFloor();
|
||||
drawInit();
|
||||
|
||||
globals.step_counter = 0;
|
||||
globals.simulation_interval = setInterval(simulationStep, Math.round(1000/config.simulation_fps));
|
||||
globals.draw_interval = setInterval(drawFrame, Math.round(1000/config.draw_fps));
|
||||
globals.draw_interval = setInterval(drawFrame, Math.round(1000 / config.draw_fps));
|
||||
globals.draw_interval = setInterval(resetSimulation, Math.round(1000 * 1000 / config.draw_fps));
|
||||
}
|
||||
|
||||
resetSimulation = function () {
|
||||
console.log('resetting walkers')
|
||||
for(var k = 0; k < config.population_size; k++) {
|
||||
globals.agents[k].walker = globals.walkers[k] = new Walker(globals.world)
|
||||
}
|
||||
}
|
||||
|
||||
simulationStep = function() {
|
||||
@@ -46,10 +89,10 @@ simulationStep = function() {
|
||||
} else {
|
||||
globals.step_counter++;
|
||||
}
|
||||
document.getElementById("generation_timer_bar").style.width = (100*globals.step_counter/config.round_length)+"%";
|
||||
if(globals.step_counter > config.round_length) {
|
||||
nextGeneration();
|
||||
}
|
||||
// document.getElementById("generation_timer_bar").style.width = (100*globals.step_counter/config.round_length)+"%";
|
||||
// if(globals.step_counter > config.round_length) {
|
||||
// nextGeneration();
|
||||
// }
|
||||
}
|
||||
|
||||
setSimulationFps = function(fps) {
|
||||
@@ -71,172 +114,39 @@ setSimulationFps = function(fps) {
|
||||
}
|
||||
|
||||
createPopulation = function(genomes) {
|
||||
setQuote();
|
||||
if(typeof globals.generation_count == 'undefined') {
|
||||
globals.generation_count = 0;
|
||||
} else {
|
||||
globals.generation_count++;
|
||||
}
|
||||
updateGeneration(globals.generation_count);
|
||||
// setQuote();
|
||||
// if(typeof globals.generation_count == 'undefined') {
|
||||
// globals.generation_count = 0;
|
||||
// } else {
|
||||
// globals.generation_count++;
|
||||
// }
|
||||
// updateGeneration(globals.generation_count);
|
||||
var walkers = [];
|
||||
var agents = []
|
||||
for(var k = 0; k < config.population_size; k++) {
|
||||
if(genomes && genomes[k]) {
|
||||
walkers.push(new Walker(globals.world, genomes[k]));
|
||||
} else {
|
||||
walkers.push(new Walker(globals.world));
|
||||
}
|
||||
if(globals.generation_count > 0 && k < config.elite_clones) {
|
||||
walkers[walkers.length - 1].is_elite = true;
|
||||
} else {
|
||||
walkers[walkers.length - 1].is_elite = false;
|
||||
}
|
||||
// walkers.push(new Walker(globals.world));
|
||||
var agent = new Agent({}, globals)
|
||||
agents.push(agent);
|
||||
walkers.push(agent.walker)
|
||||
|
||||
}
|
||||
return walkers;
|
||||
return [agents, walkers];
|
||||
}
|
||||
|
||||
randAction= function(){
|
||||
var action = []
|
||||
for (let i = 0; i < 12; i++) {
|
||||
action.push(Math.randf(-1,1))
|
||||
}
|
||||
return action
|
||||
}
|
||||
|
||||
populationSimulationStep = function() {
|
||||
var dead_dudes = 0;
|
||||
for(var k = 0; k < config.population_size; k++) {
|
||||
if(globals.walkers[k].health > 0) {
|
||||
globals.walkers[k].simulationStep();
|
||||
} else {
|
||||
if(!globals.walkers[k].is_dead) {
|
||||
for(var l = 0; l < globals.walkers[k].bodies.length; l++) {
|
||||
if(globals.walkers[k].bodies[l]) {
|
||||
globals.world.DestroyBody(globals.walkers[k].bodies[l]);
|
||||
globals.walkers[k].bodies[l] = null;
|
||||
}
|
||||
}
|
||||
globals.walkers[k].is_dead = true;
|
||||
}
|
||||
dead_dudes++;
|
||||
}
|
||||
}
|
||||
printNames(globals.walkers);
|
||||
if(dead_dudes >= config.population_size) {
|
||||
nextGeneration();
|
||||
// var action = randAction()
|
||||
// globals.walkers[k].simulationStep(action);
|
||||
globals.agents[k].step()
|
||||
// console.log(globals.walkers[k].walker.getState())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nextGeneration = function() {
|
||||
if(globals.simulation_interval)
|
||||
clearInterval(globals.simulation_interval);
|
||||
if(globals.draw_interval)
|
||||
clearInterval(globals.draw_interval);
|
||||
getInterfaceValues();
|
||||
var genomes = createNewGenerationGenomes();
|
||||
killGeneration();
|
||||
globals.walkers = createPopulation(genomes);
|
||||
resetCamera();
|
||||
globals.step_counter = 0;
|
||||
globals.simulation_interval = setInterval(simulationStep, Math.round(1000/config.simulation_fps));
|
||||
if(config.draw_fps > 0) {
|
||||
globals.draw_interval = setInterval(drawFrame, Math.round(1000/config.draw_fps));
|
||||
}
|
||||
}
|
||||
|
||||
killGeneration = function() {
|
||||
for(var k = 0; k < globals.walkers.length; k++) {
|
||||
for(var l = 0; l < globals.walkers[k].bodies.length; l++) {
|
||||
if(globals.walkers[k].bodies[l])
|
||||
globals.world.DestroyBody(globals.walkers[k].bodies[l]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createNewGenerationGenomes = function() {
|
||||
globals.walkers.sort(function(a,b) {
|
||||
return b[config.fitness_criterium] - a[config.fitness_criterium];
|
||||
});
|
||||
if(typeof globals.last_record == 'undefined') {
|
||||
globals.last_record = 0;
|
||||
}
|
||||
if(globals.walkers[0][config.fitness_criterium] > globals.last_record) {
|
||||
printChampion(globals.walkers[0]);
|
||||
globals.last_record = globals.walkers[0][config.fitness_criterium];
|
||||
}
|
||||
|
||||
var genomes = [];
|
||||
var parents = null;
|
||||
// clones
|
||||
for(var k = 0; k < config.elite_clones; k++) {
|
||||
genomes.push(globals.walkers[k].genome);
|
||||
}
|
||||
for(var k = config.elite_clones; k < config.population_size; k++) {
|
||||
if(parents = pickParents()) {
|
||||
genomes.push(copulate(globals.walkers[parents[0]], globals.walkers[parents[1]]));
|
||||
}
|
||||
}
|
||||
genomes = mutateClones(genomes);
|
||||
return genomes;
|
||||
}
|
||||
|
||||
pickParents = function() {
|
||||
var parents = [];
|
||||
for(var k = 0; k < config.population_size; k++) {
|
||||
if(Math.random() < (1/(k+2))) {
|
||||
parents.push(k);
|
||||
if(parents.length >= 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(typeof parents[0] == 'undefined' || typeof parents[1] == 'undefined') {
|
||||
return false;
|
||||
}
|
||||
return parents;
|
||||
}
|
||||
|
||||
copulate = function(walker_1, walker_2) {
|
||||
var new_genome = [];
|
||||
for(var k = 0; k < walker_1.genome.length; k++) {
|
||||
if(Math.random() < 0.5) {
|
||||
var parent = walker_1;
|
||||
} else {
|
||||
var parent = walker_2
|
||||
}
|
||||
var new_gene = JSON.parse(JSON.stringify(parent.genome[k]));
|
||||
for(var g in walker_1.genome[k]) {
|
||||
if(walker_1.genome[k].hasOwnProperty(g)) {
|
||||
if(Math.random() < config.mutation_chance) {
|
||||
if(g.indexOf('target') >= 0) {
|
||||
new_gene[g] = Math.floor(Math.random() * walker_1.bodies.length);
|
||||
} else {
|
||||
new_gene[g] = new_gene[g] * (1 + config.mutation_amount*(Math.random()*2 - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new_genome[k] = new_gene;
|
||||
}
|
||||
return new_genome;
|
||||
}
|
||||
|
||||
mutateClones = function(genomes) {
|
||||
if(parseFloat(config.mutation_chance) == 0) {
|
||||
return genomes;
|
||||
}
|
||||
|
||||
for(var k = 0; k < genomes.length; k++) {
|
||||
var current = JSON.stringify(genomes[k]);
|
||||
for(var l = k + 1; l < genomes.length; l++) {
|
||||
if(current == JSON.stringify(genomes[l])) {
|
||||
var to_mutate = Math.floor(Math.random() * genomes[l].length);
|
||||
for(var g in genomes[l][to_mutate]) {
|
||||
if(genomes[l][to_mutate].hasOwnProperty(g)) {
|
||||
if(g.indexOf('target') < 0) {
|
||||
genomes[l][to_mutate][g] = genomes[l][to_mutate][g] * (1 + config.mutation_amount*(Math.random()*2 - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return genomes;
|
||||
}
|
||||
|
||||
getInterfaceValues = function() {
|
||||
config.elite_clones = document.getElementById("elite_clones").value;
|
||||
config.mutation_chance = document.getElementById("mutation_chance").value
|
||||
config.mutation_amount = document.getElementById("mutation_amount").value
|
||||
}
|
||||
-131
@@ -1,131 +0,0 @@
|
||||
quotes = [
|
||||
"The Ministry of Silly Walks on steroids",
|
||||
"It's like watching other people QWOP",
|
||||
"Keep tumbling",
|
||||
"As seen on a negative comment on Reddit",
|
||||
"The Walking Sad",
|
||||
"The Walking Fad",
|
||||
"Army of QWOP",
|
||||
"Nice me-and-my-friends-leaving-the-bar-at-2am simulator!"
|
||||
];
|
||||
|
||||
printNames = function(walkers) {
|
||||
var name_list = document.getElementById("name_list");
|
||||
name_list.innerHTML = "";
|
||||
for(var k = 0; k < walkers.length; k++) {
|
||||
var tr = document.createElement("TR");
|
||||
if(walkers[k].is_elite) {
|
||||
tr.className = "elite_name";
|
||||
}
|
||||
var td = document.createElement("TD");
|
||||
td.className = "name";
|
||||
td.appendChild(document.createTextNode(walkers[k].name));
|
||||
tr.appendChild(td);
|
||||
|
||||
td = document.createElement("TD");
|
||||
td.className = "score";
|
||||
td.appendChild(document.createTextNode(walkers[k][config.fitness_criterium].toFixed(2)));
|
||||
tr.appendChild(td);
|
||||
name_list.appendChild(tr);
|
||||
}
|
||||
}
|
||||
|
||||
printChampion = function(walker) {
|
||||
var champ_list = document.getElementById("champ_list");
|
||||
var tr = document.createElement("TR");
|
||||
|
||||
var cur_rows = champ_list.getElementsByTagName("TR");
|
||||
if(cur_rows.length >= config.population_size) {
|
||||
champ_list.removeChild(cur_rows[0]);
|
||||
}
|
||||
|
||||
var td = document.createElement("TD");
|
||||
td.className = "generation";
|
||||
td.appendChild(document.createTextNode(globals.generation_count));
|
||||
tr.appendChild(td);
|
||||
|
||||
td = document.createElement("TD");
|
||||
td.className = "name";
|
||||
td.appendChild(document.createTextNode(walker.name));
|
||||
tr.appendChild(td);
|
||||
|
||||
td = document.createElement("TD");
|
||||
td.className = "score";
|
||||
td.appendChild(document.createTextNode(walker[config.fitness_criterium].toFixed(2)));
|
||||
tr.appendChild(td);
|
||||
|
||||
champ_list.appendChild(tr);
|
||||
}
|
||||
|
||||
updateGeneration = function(number) {
|
||||
document.getElementById("gen_number").innerHTML = number;
|
||||
}
|
||||
|
||||
setQuote = function() {
|
||||
document.getElementById("page_quote").innerHTML = '"'+quotes[Math.floor(Math.random() * quotes.length)]+'"';
|
||||
}
|
||||
|
||||
interfaceSetup = function() {
|
||||
var mut_chance_sel = document.getElementById("mutation_chance");
|
||||
for(var k = 0; k < mut_chance_sel.options.length; k++) {
|
||||
if(mut_chance_sel.options[k].value == config.mutation_chance) {
|
||||
mut_chance_sel.options[k].selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var mut_amount_sel = document.getElementById("mutation_amount");
|
||||
for(var k = 0; k < mut_amount_sel.options.length; k++) {
|
||||
if(mut_amount_sel.options[k].value == config.mutation_amount) {
|
||||
mut_amount_sel.options[k].selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var elite_clones_sel = document.getElementById("elite_clones");
|
||||
for(var k = 0; k <= config.population_size; k++) {
|
||||
var option = document.createElement("OPTION");
|
||||
option.value = k;
|
||||
option.label = k;
|
||||
if(k == config.elite_clones) {
|
||||
option.selected = true;
|
||||
}
|
||||
elite_clones_sel.appendChild(option);
|
||||
}
|
||||
|
||||
var round_length_sel = document.getElementById("round_length");
|
||||
for(var k = 0; k <= round_length_sel.options.length; k++) {
|
||||
if(round_length_sel.options[k].value == config.round_length) {
|
||||
round_length_sel.options[k].selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
round_length_sel.onchange = function() {
|
||||
config.round_length = round_length_sel.value;
|
||||
}
|
||||
|
||||
var fps_sel = document.getElementById("draw_fps");
|
||||
for(var k = 0; k < fps_sel.options.length; k++) {
|
||||
if(fps_sel.options[k].value == config.draw_fps) {
|
||||
fps_sel.options[k].selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fps_sel.onchange = function() {
|
||||
setFps(fps_sel.value);
|
||||
}
|
||||
|
||||
var simulation_fps_sel = document.getElementById("simulation_fps");
|
||||
for(var k = 0; k < simulation_fps_sel.options.length; k++) {
|
||||
if(simulation_fps_sel.options[k].value == config.simulation_fps) {
|
||||
simulation_fps_sel.options[k].selected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
simulation_fps_sel.onchange = function() {
|
||||
setSimulationFps(simulation_fps_sel.value);
|
||||
}
|
||||
|
||||
}
|
||||
+21
-94
@@ -6,8 +6,7 @@ var Walker = function() {
|
||||
this.__constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Walker.prototype.__constructor = function(world, genome) {
|
||||
|
||||
Walker.prototype.__constructor = function(world) {
|
||||
this.world = globals.world;
|
||||
|
||||
this.density = 106.2; // common for all fixtures, no reason to be too specific
|
||||
@@ -19,7 +18,10 @@ Walker.prototype.__constructor = function(world, genome) {
|
||||
this.head_height = 0;
|
||||
this.steps = 0;
|
||||
|
||||
this.bd = new b2.BodyDef();
|
||||
this.hue = Math.randf(200,360)
|
||||
|
||||
this.bd = new b2.BodyDef({positions: {x:10, y:-10}});
|
||||
this.bd.position.x += Math.randf(-10, 10)
|
||||
this.bd.type = b2.Body.b2_dynamicBody;
|
||||
this.bd.linearDamping = 0;
|
||||
this.bd.angularDamping = 0.01;
|
||||
@@ -73,14 +75,6 @@ Walker.prototype.__constructor = function(world, genome) {
|
||||
this.connectParts();
|
||||
|
||||
this.bodies = this.getBodies();
|
||||
|
||||
if(genome) {
|
||||
this.genome = JSON.parse(JSON.stringify(genome));
|
||||
} else {
|
||||
this.genome = this.createGenome(this.joints, this.bodies);
|
||||
}
|
||||
|
||||
this.name = this.makeName(this.genome);
|
||||
}
|
||||
|
||||
Walker.prototype.createTorso = function() {
|
||||
@@ -229,18 +223,6 @@ Walker.prototype.createHead = function() {
|
||||
}
|
||||
|
||||
Walker.prototype.connectParts = function() {
|
||||
// neck/torso
|
||||
// var jd = new b2.RevoluteJointDef();
|
||||
// var position = this.head.neck.GetPosition().Clone();
|
||||
// position.y -= this.head_def.neck_height/2;
|
||||
// jd.Initialize(this.head.neck, this.torso.upper_torso, position);
|
||||
// jd.lowerAngle = 0;
|
||||
// jd.upperAngle = 0.2;
|
||||
// jd.enableLimit = true;
|
||||
// jd.maxMotorTorque = 2;
|
||||
// jd.motorSpeed = 0;
|
||||
// jd.enableMotor = true;
|
||||
// this.joints.push(this.world.CreateJoint(jd));
|
||||
|
||||
//neck/torso
|
||||
var jd = new b2.WeldJointDef();
|
||||
@@ -318,54 +300,27 @@ Walker.prototype.getBodies = function() {
|
||||
];
|
||||
}
|
||||
|
||||
Walker.prototype.createGenome = function(joints, bodies) {
|
||||
var genome = [];
|
||||
for(var k = 0; k < joints.length; k++) {
|
||||
var gene = new Object();
|
||||
/*
|
||||
gene.target_body1 = Math.floor(Math.random() * bodies.length);
|
||||
gene.target_body2 = Math.floor(Math.random() * bodies.length);
|
||||
gene.target_body3 = Math.floor(Math.random() * bodies.length);
|
||||
gene.body_cos_multiplier1 = 6*Math.random() - 3;
|
||||
gene.body_cos_multiplier2 = 6*Math.random() - 3;
|
||||
gene.body_cos_multiplier3 = 6*Math.random() - 3;
|
||||
|
||||
gene.torso_angle_multiplier = 4*Math.random() -2;
|
||||
*/
|
||||
gene.cos_factor = 6*Math.random() - 3;
|
||||
gene.time_factor = Math.random()/10;
|
||||
gene.time_shift = Math.random()*Math.PI/2
|
||||
genome.push(gene);
|
||||
}
|
||||
return genome;
|
||||
Walker.prototype.getState = function () {
|
||||
return this.bodies
|
||||
.map(b => b.GetPosition())
|
||||
.reduce((o, p) => { o.push(p.x); o.push(p.y); return o }, [])
|
||||
}
|
||||
|
||||
Walker.prototype.simulationStep = function() {
|
||||
Walker.prototype.simulationStep = function (motorSpeeds) {
|
||||
|
||||
// act
|
||||
for(var k = 0; k < this.joints.length; k++) {
|
||||
/*
|
||||
var target_body1 = this.bodies[this.genome[k].target_body1];
|
||||
var target_body2 = this.bodies[this.genome[k].target_body2];
|
||||
var target_body3 = this.bodies[this.genome[k].target_body3];
|
||||
|
||||
var sin1 = Math.sin(target_body1.GetAngle());
|
||||
var sin2 = Math.sin(target_body2.GetAngle());
|
||||
var sin3 = Math.sin(target_body3.GetAngle());
|
||||
|
||||
this.joints[k].SetMotorSpeed(
|
||||
this.genome[k].cos_factor * Math.sin(this.genome[k].torso_angle_multiplier*this.torso.upper_torso.GetAngle()) +
|
||||
this.genome[k].body_cos_multiplier1 * sin1 +
|
||||
this.genome[k].body_cos_multiplier2 * sin2 +
|
||||
this.genome[k].body_cos_multiplier3 * sin3
|
||||
);
|
||||
*/
|
||||
this.joints[k].SetMotorSpeed(this.genome[k].cos_factor*Math.cos(this.genome[k].time_shift+this.genome[k].time_factor*globals.step_counter));
|
||||
// var oldSpeed = this.joints[k].GetMotorSpeed()
|
||||
// this.joints[k].SetMotorSpeed(oldSpeed + motorSpeeds[k]/10); // action can range from -3 to 3, radians per second
|
||||
this.joints[k].SetMotorSpeed(motorSpeeds[k]*3); // action can range from -3 to 3, radians per second
|
||||
}
|
||||
var oldmax = this.max_distance;
|
||||
var distance = this.torso.upper_torso.GetPosition().x;
|
||||
this.max_distance = Math.max(this.max_distance, distance);
|
||||
|
||||
// score
|
||||
this.head_height = this.head.head.GetPosition().y;
|
||||
/* score/reward */
|
||||
// it's head should be above it's feet
|
||||
this.head_height = this.head.head.GetPosition().y;
|
||||
this.low_foot_height = Math.min(this.left_leg.foot.GetPosition().y, this.right_leg.foot.GetPosition().y);
|
||||
var body_delta = this.head_height-this.low_foot_height;
|
||||
var leg_delta = this.right_leg.foot.GetPosition().x - this.left_leg.foot.GetPosition().x;
|
||||
@@ -386,38 +341,10 @@ Walker.prototype.simulationStep = function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.health = this.score * 800 + 10
|
||||
// console.log(body_delta, leg_delta)
|
||||
|
||||
|
||||
if(config.check_health) {
|
||||
if(body_delta < config.instadeath_delta) {
|
||||
this.health = 0;
|
||||
} else {
|
||||
this.health--;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Walker.prototype.makeName = function(genome) {
|
||||
var name = '';
|
||||
var vowels = ['a','e','i','o','u'];
|
||||
var space_position = Math.floor(genome.length/2);
|
||||
for(var k = 0; k < genome.length; k++) {
|
||||
var sum = 0;
|
||||
for(var l in genome[k]) {
|
||||
if(genome[k].hasOwnProperty(l)) {
|
||||
sum += (genome[k][l]*10);
|
||||
}
|
||||
sum = Math.abs(Math.floor(sum));
|
||||
}
|
||||
if(k == space_position) {
|
||||
name += ' ';
|
||||
}
|
||||
if(k%2) {
|
||||
name += vowels[sum%5];
|
||||
} else {
|
||||
name += String.fromCharCode(97+sum%26);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "2d_walker_rl_js",
|
||||
"version": "0.0.1",
|
||||
"description": "TODO: Write a project description",
|
||||
"main": "index.js",
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Jackymancs4/boxidroid.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Jackymancs4/boxidroid/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Jackymancs4/boxidroid#readme"
|
||||
}
|
||||
Vendored
+2
-1
File diff suppressed because one or more lines are too long
Vendored
+4908
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user