simondevyoutube 5 vuotta sitten
vanhempi
commit
20475f0df8
5 muutettua tiedostoa jossa 240 lisäystä ja 206 poistoa
  1. 150 0
      bird.js
  2. 0 1
      index.html
  3. 33 198
      main.js
  4. 57 0
      pipe.js
  5. 0 7
      population.js

+ 150 - 0
bird.js

@@ -0,0 +1,150 @@
+import {ffnet} from "./ffnet.js";
+
+
+export const bird = (function() {
+
+  const _BIRD_POS_X = 50;
+
+  class _FlappyBirdObject {
+    constructor(scene) {
+      this._scene = scene;
+      this._sprite = scene.add.sprite(_BIRD_POS_X, 100, 'bird');
+      this._spriteTint = scene.add.sprite(_BIRD_POS_X, 100, 'bird-colour');
+      this._velocity = 0;
+      this._dead = false;
+    }
+
+    Destroy() {
+      this._sprite.destroy();
+    }
+
+    Update(params) {
+      if (this._dead) {
+        return;
+      }
+
+      this._ApplyGravity(params.timeElapsed)
+      this._velocity = Math.min(Math.max(
+          this._velocity, this._config.max_upwards_velocity), this._config.terminal_velocity);
+      this._sprite.y += this._velocity * params.timeElapsed;
+      this._spriteTint.y += this._velocity * params.timeElapsed;
+
+      const v = new Phaser.Math.Vector2(
+          -1 * this._config.treadmill_speed * params.timeElapsed, 0);
+      v.add(new Phaser.Math.Vector2(0, this._velocity));
+      v.normalize();
+
+      const rad = Math.atan2(v.y, v.x);
+      const deg = (180.0 / Math.PI) * rad;
+
+      this._sprite.angle = deg * 0.75;
+      this._spriteTint.angle = deg * 0.75;
+    }
+
+    get Dead() {
+      return this._dead;
+    }
+
+    set Dead(d) {
+      this._dead = d;
+
+      this._scene.tweens.add({
+          targets: this._sprite,
+          props: {
+              alpha: { value: 0.0, duration: 500, ease: 'Sine.easeInOut' },
+          },
+      });
+      this._scene.tweens.add({
+          targets: this._spriteTint,
+          props: {
+              alpha: { value: 0.0, duration: 500, ease: 'Sine.easeInOut' },
+          },
+      });
+    }
+
+    set Alpha(a) {
+      this._sprite.alpha = a;
+      this._spriteTint.alpha = a;
+    }
+
+    get Bounds() {
+      return this._sprite.getBounds();
+    }
+
+    _ApplyGravity(timeElapsed) {
+      this._velocity += this._config.gravity * timeElapsed;
+    }
+  }
+
+  class FlappyBird_Manual extends _FlappyBirdObject {
+    constructor(scene) {
+      super(scene);
+
+      this._frameInputs = [];
+    }
+
+    Update(params) {
+      this._HandleInput(params);
+
+      super.Update(params);
+    }
+
+    _HandleInput(params) {
+      if (!params.keys.up) {
+        return;
+      }
+
+      this._velocity += _UPWARDS_ACCELERATION;
+    }
+  }
+
+  class FlappyBird_NeuralNet extends _FlappyBirdObject {
+    constructor(config) {
+      super(config.scene);
+
+      this._model = new ffnet.FFNeuralNetwork(config.pop_params.shapes);
+      this._model.fromArray(config.pop_entity.genotype);
+      this._populationEntity = config.pop_entity;
+      this._spriteTint.setTint(config.pop_params.tint);
+      this._config = config;
+    }
+
+    Update(params) {
+      function _PipeParams(bird, pipe) {
+        const distToPipe = (
+            (pipe.X + pipe.Width) - bird.Bounds.left) / bird._config.config_width;
+        const distToPipeB = (
+            (pipe._sprite1.y - bird.Bounds.bottom) / bird._config.config_height) * 0.5 + 0.5;
+        const distToPipeT = (
+            (pipe._sprite2.y - bird.Bounds.top) / bird._config.config_height) * 0.5 + 0.5;
+        return [distToPipe, distToPipeB, distToPipeT];
+      }
+
+      function _Params(bird, pipes) {
+        const inputs = pipes.map(p => _PipeParams(bird, p)).flat();
+
+        inputs.push((bird._velocity / bird._config.gravity) * 0.5 + 0.5);
+
+        return inputs;
+      }
+
+      const inputs = _Params(this, params.nearestPipes);
+      const decision = this._model.predict(inputs);
+
+      if (decision > 0.5) {
+        this._velocity += this._config.acceleration;
+      }
+
+      super.Update(params);
+
+      if (!this.Dead) {
+        this._populationEntity.fitness += params.timeElapsed;
+      }
+    }
+  }
+
+  return {
+    FlappyBird_Manual: FlappyBird_Manual,
+    FlappyBird_NeuralNet: FlappyBird_NeuralNet
+  };
+})();

+ 0 - 1
index.html

@@ -2,7 +2,6 @@
 <html>
 <html>
   <head>
   <head>
       <script src="https://cdn.jsdelivr.net/npm/phaser/dist/phaser.js"></script>
       <script src="https://cdn.jsdelivr.net/npm/phaser/dist/phaser.js"></script>
-      <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
   </head>
   </head>
   <body>
   <body>
     <style>
     <style>

+ 33 - 198
main.js

@@ -1,12 +1,14 @@
+import {bird} from "./bird.js";
 import {ffnet} from "./ffnet.js";
 import {ffnet} from "./ffnet.js";
+import {pipe} from "./pipe.js";
 import {population} from "./population.js"
 import {population} from "./population.js"
 
 
 const _GRAVITY = 900;
 const _GRAVITY = 900;
 const _TERMINAL_VELOCITY = 400;
 const _TERMINAL_VELOCITY = 400;
 const _MAX_UPWARDS_VELOCITY = -300;
 const _MAX_UPWARDS_VELOCITY = -300;
 const _UPWARDS_ACCELERATION = -450;
 const _UPWARDS_ACCELERATION = -450;
+const _PIPE_SPACING_X = 250;
 const _PIPE_SPACING_Y = 100;
 const _PIPE_SPACING_Y = 100;
-const _PIPE_SPACING_X = 200;
 const _TREADMILL_SPEED = -125;
 const _TREADMILL_SPEED = -125;
 
 
 const _CONFIG_WIDTH = 960;
 const _CONFIG_WIDTH = 960;
@@ -15,192 +17,6 @@ const _GROUND_Y = _CONFIG_HEIGHT;
 const _BIRD_POS_X = 50;
 const _BIRD_POS_X = 50;
 
 
 
 
-class PipePairObject {
-  constructor(scene, x) {
-    const height = _CONFIG_HEIGHT * (0.25 + 0.5 * Math.random());
-    this._sprite1 = scene.add.sprite(x, height + _PIPE_SPACING_Y * 0.5, 'pipe');
-    this._sprite1.displayOriginX = 0;
-    this._sprite1.displayOriginY = 0;
-
-    this._sprite2 = scene.add.sprite(x, height - _PIPE_SPACING_Y * 0.5, 'pipe');
-    this._sprite2.displayOriginX = 0;
-    this._sprite2.displayOriginY = 0;
-    this._sprite2.displayHeight = -1 * this._sprite2.height;
-  }
-
-  Destroy() {
-    this._sprite1.destroy();
-    this._sprite2.destroy();
-  }
-
-  Update(timeElapsed) {
-    this._sprite1.x += timeElapsed * _TREADMILL_SPEED;
-    this._sprite2.x += timeElapsed * _TREADMILL_SPEED;
-  }
-
-  Intersects(aabb) {
-    const b1 = this._sprite1.getBounds();
-    const b2 = this._sprite2.getBounds();
-    b2.y -= this._sprite2.height;
-    return (
-        Phaser.Geom.Intersects.RectangleToRectangle(b1, aabb) ||
-        Phaser.Geom.Intersects.RectangleToRectangle(b2, aabb));
-  }
-
-  Reset(x) {
-    const height = _CONFIG_HEIGHT * (0.25 + 0.5 * Math.random());
-    this._sprite1.x = x;
-    this._sprite1.y = height + _PIPE_SPACING_Y * 0.5;
-    this._sprite2.x = x;
-    this._sprite2.y = height - _PIPE_SPACING_Y * 0.5;
-  }
-
-  get X() {
-    return this._sprite1.x;
-  }
-
-  get Width() {
-    return this._sprite1.width;
-  }
-}
-
-class FlappyBirdObject {
-  constructor(scene) {
-    this._scene = scene;
-    this._sprite = scene.add.sprite(_BIRD_POS_X, 100, 'bird');
-    this._spriteTint = scene.add.sprite(_BIRD_POS_X, 100, 'bird-colour');
-    this._velocity = 0;
-    this._dead = false;
-  }
-
-  Destroy() {
-    this._sprite.destroy();
-  }
-
-  Update(params) {
-    if (this._dead) {
-      return;
-    }
-
-    this._ApplyGravity(params.timeElapsed)
-    this._velocity = Math.min(Math.max(
-        this._velocity, _MAX_UPWARDS_VELOCITY), _TERMINAL_VELOCITY);
-    this._sprite.y += this._velocity * params.timeElapsed;
-    this._spriteTint.y += this._velocity * params.timeElapsed;
-
-    const v = new Phaser.Math.Vector2(
-        -1 * _TREADMILL_SPEED * params.timeElapsed, 0);
-    v.add(new Phaser.Math.Vector2(0, this._velocity));
-    v.normalize();
-
-    const rad = Math.atan2(v.y, v.x);
-    const deg = (180.0 / Math.PI) * rad;
-
-    this._sprite.angle = deg * 0.75;
-    this._spriteTint.angle = deg * 0.75;
-  }
-
-  get Dead() {
-    return this._dead;
-  }
-
-  set Dead(d) {
-    this._dead = d;
-
-    this._scene.tweens.add({
-        targets: this._sprite,
-        props: {
-            alpha: { value: 0.0, duration: 500, ease: 'Sine.easeInOut' },
-        },
-    });
-    this._scene.tweens.add({
-        targets: this._spriteTint,
-        props: {
-            alpha: { value: 0.0, duration: 500, ease: 'Sine.easeInOut' },
-        },
-    });
-  }
-
-  set Alpha(a) {
-    this._sprite.alpha = a;
-    this._spriteTint.alpha = a;
-  }
-
-  get Bounds() {
-    return this._sprite.getBounds();
-  }
-
-  _ApplyGravity(timeElapsed) {
-    this._velocity += _GRAVITY * timeElapsed;
-  }
-}
-
-class FlappyBird_Manual extends FlappyBirdObject {
-  constructor(scene) {
-    super(scene);
-
-    this._frameInputs = [];
-  }
-
-  Update(params) {
-    this._HandleInput(params);
-
-    super.Update(params);
-  }
-
-  _HandleInput(params) {
-    if (!params.keys.up) {
-      return;
-    }
-
-    this._velocity += _UPWARDS_ACCELERATION;
-  }
-}
-
-class FlappyBird_NeuralNet extends FlappyBirdObject {
-  constructor(scene, populationEntity, params) {
-    super(scene);
-
-    this._model = new ffnet.FFNeuralNetwork(params.shapes);
-    this._model.fromArray(populationEntity.genotype);
-    this._populationEntity = populationEntity;
-    this._spriteTint.setTint(params.tint);
-  }
-
-  Update(params) {
-    function _PipeParams(bird, pipe) {
-      const distToPipe = (
-          (pipe.X + pipe.Width) - bird.Bounds.left) / _CONFIG_WIDTH;
-      const distToPipeB = (
-          (pipe._sprite1.y - bird.Bounds.bottom) / _CONFIG_HEIGHT) * 0.5 + 0.5;
-      const distToPipeT = (
-          (pipe._sprite2.y - bird.Bounds.top) / _CONFIG_HEIGHT) * 0.5 + 0.5;
-      return [distToPipe, distToPipeB, distToPipeT];
-    }
-
-    function _Params(bird, pipes) {
-      const inputs = pipes.map(p => _PipeParams(bird, p)).flat();
-
-      inputs.push((bird._velocity / _GRAVITY) * 0.5 + 0.5);
-
-      return inputs;
-    }
-
-    const inputs = _Params(this, params.nearestPipes);
-    const decision = this._model.predict(inputs);
-
-    if (decision > 0.5) {
-      this._velocity += _UPWARDS_ACCELERATION;
-    }
-
-    super.Update(params);
-
-    if (!this.Dead) {
-      this._populationEntity.fitness += params.timeElapsed;
-    }
-  }
-}
-
 class FlappyBirdGame {
 class FlappyBirdGame {
   constructor() {
   constructor() {
     this._game = this._CreateGame();
     this._game = this._CreateGame();
@@ -225,21 +41,21 @@ class FlappyBirdGame {
 
 
     const NN_DEF2 = [
     const NN_DEF2 = [
         {size: 7},
         {size: 7},
-        {size: 12, activation: ffnet.relu},
+        {size: 9, activation: ffnet.relu},
         {size: 1, activation: ffnet.sigmoid}
         {size: 1, activation: ffnet.sigmoid}
     ];
     ];
 
 
     const NN_DEF3 = [
     const NN_DEF3 = [
         {size: 7},
         {size: 7},
-        {size: 8, activation: ffnet.relu},
-        {size: 8, activation: ffnet.relu},
+        {size: 9, activation: ffnet.relu},
+        {size: 9, activation: ffnet.relu},
         {size: 1, activation: ffnet.sigmoid}
         {size: 1, activation: ffnet.sigmoid}
     ];
     ];
 
 
     this._populations = [
     this._populations = [
-      this._CreatePopulation(64, NN_DEF1, 0xFF0000),
-      this._CreatePopulation(64, NN_DEF2, 0x0000FF),
-      this._CreatePopulation(64, NN_DEF3, 0x00FF00),
+      this._CreatePopulation(100, NN_DEF1, 0xFF0000),
+      this._CreatePopulation(100, NN_DEF2, 0x0000FF),
+      this._CreatePopulation(100, NN_DEF3, 0x00FF00),
     ];
     ];
   }
   }
 
 
@@ -252,7 +68,7 @@ class FlappyBirdGame {
         size: t.toArray().length,
         size: t.toArray().length,
       },
       },
       mutation: {
       mutation: {
-        magnitude: 0.5,
+        magnitude: 0.1,
         odds: 0.1,
         odds: 0.1,
         decay: 0,
         decay: 0,
       },
       },
@@ -288,7 +104,13 @@ class FlappyBirdGame {
   _Init() {
   _Init() {
     for (let i = 0; i < 5; i+=1) {
     for (let i = 0; i < 5; i+=1) {
       this._pipes.push(
       this._pipes.push(
-          new PipePairObject(this._scene, 500 + i * _PIPE_SPACING_X));
+          new pipe.PipePairObject({
+            scene: this._scene,
+            x: 500 + i * _PIPE_SPACING_X,
+            spacing: _PIPE_SPACING_Y,
+            speed: _TREADMILL_SPEED,
+            config_height: _CONFIG_HEIGHT
+          }));
     }
     }
 
 
     this._gameOver = false;
     this._gameOver = false;
@@ -321,8 +143,20 @@ class FlappyBirdGame {
       curPop.Step();
       curPop.Step();
 
 
       this._birds.push(...curPop._population.map(
       this._birds.push(...curPop._population.map(
-          p => new FlappyBird_NeuralNet(
-              this._scene, p, curPop._params)));
+          p => new bird.FlappyBird_NeuralNet(
+              {
+                scene: this._scene,
+                pop_entity: p,
+                pop_params: curPop._params,
+                x: _BIRD_POS_X,
+                config_width: _CONFIG_WIDTH,
+                config_height: _CONFIG_HEIGHT,
+                max_upwards_velocity: _MAX_UPWARDS_VELOCITY,
+                terminal_velocity: _TERMINAL_VELOCITY,
+                treadmill_speed: _TREADMILL_SPEED,
+                acceleration: _UPWARDS_ACCELERATION,
+                gravity: _GRAVITY
+              })));
     }
     }
   }
   }
 
 
@@ -338,8 +172,9 @@ class FlappyBirdGame {
         scale: {
         scale: {
           mode: Phaser.Scale.FIT,
           mode: Phaser.Scale.FIT,
           autoCenter: Phaser.Scale.CENTER_BOTH,
           autoCenter: Phaser.Scale.CENTER_BOTH,
+          treadmill_speed: _TREADMILL_SPEED,
           width: _CONFIG_WIDTH,
           width: _CONFIG_WIDTH,
-          height: _CONFIG_HEIGHT
+          height: _CONFIG_HEIGHT,
         }
         }
     };
     };
 
 

+ 57 - 0
pipe.js

@@ -0,0 +1,57 @@
+export const pipe = (function() {
+
+
+  class _PipePairObject {
+    constructor(config) {
+      this._config = config;
+      const height = config.config_height * (0.25 + 0.5 * Math.random());
+      this._sprite1 = config.scene.add.sprite(config.x, height + config.spacing * 0.5, 'pipe');
+      this._sprite1.displayOriginX = 0;
+      this._sprite1.displayOriginY = 0;
+  
+      this._sprite2 = config.scene.add.sprite(config.x, height - config.spacing * 0.5, 'pipe');
+      this._sprite2.displayOriginX = 0;
+      this._sprite2.displayOriginY = 0;
+      this._sprite2.displayHeight = -1 * this._sprite2.height;
+    }
+  
+    Destroy() {
+      this._sprite1.destroy();
+      this._sprite2.destroy();
+    }
+  
+    Update(timeElapsed) {
+      this._sprite1.x += timeElapsed * this._config.speed;
+      this._sprite2.x += timeElapsed * this._config.speed;
+    }
+  
+    Intersects(aabb) {
+      const b1 = this._sprite1.getBounds();
+      const b2 = this._sprite2.getBounds();
+      b2.y -= this._sprite2.height;
+      return (
+          Phaser.Geom.Intersects.RectangleToRectangle(b1, aabb) ||
+          Phaser.Geom.Intersects.RectangleToRectangle(b2, aabb));
+    }
+  
+    Reset(x) {
+      const height = this._config.config_height * (0.25 + 0.5 * Math.random());
+      this._sprite1.x = x;
+      this._sprite1.y = height + this._config.spacing * 0.5;
+      this._sprite2.x = x;
+      this._sprite2.y = height - this._config.spacing * 0.5;
+    }
+  
+    get X() {
+      return this._sprite1.x;
+    }
+  
+    get Width() {
+      return this._sprite1.width;
+    }
+  }
+
+  return {
+    PipePairObject: _PipePairObject
+  };
+})();

+ 0 - 7
population.js

@@ -68,13 +68,6 @@ export const population = (function() {
           const p1 = top[i];
           const p1 = top[i];
           const p2 = _RandomParent(parents, p1, totalFitness);
           const p2 = _RandomParent(parents, p1, totalFitness);
 
 
-          // const g = [];
-          // for (let r = 0; r < p1.genotype.length; r++ ) {
-          //   const roll = Math.random();
-          //   g.push(roll < 0.5 ? p1.genotype[r] : p2.genotype[r]);
-          // }
-          // newPopulation.push(_CopyGenotype({fitness: 1, genotype: g}));
-
           const index = Math.round(Math.random() * p1.genotype.length);
           const index = Math.round(Math.random() * p1.genotype.length);
 
 
           const g = p1.genotype.slice(0, index).concat(
           const g = p1.genotype.slice(0, index).concat(