Skip to content

Commit

Permalink
Glue everything toghether
Browse files Browse the repository at this point in the history
Add trainer
Add brain to dinos and use it to control movement
Connect players and ga individuals
  • Loading branch information
U1F30C committed Nov 27, 2020
1 parent b99b70d commit a9ac77c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 23 deletions.
25 changes: 25 additions & 0 deletions src/ai/Trainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { GeneticAlgorithm } from './ga';
import { Network } from './ann/Network';
const { weightsForArchitecture } = require('./ann/math');
const { times } = require('lodash');
export class Trainer {
constructor(populationSize) {
// this.population = times(populationSize, () => ({}));

const networkArchitecture = [[2], [4, 'sigmoid'], [4, 'sigmoid'], [2, 'sigmoid']];

this.ga = new GeneticAlgorithm(populationSize, {
dimentions: weightsForArchitecture(networkArchitecture.map(([n]) => n)),
min: -10,
max: 10,
});
this.population = this.ga.population.map((individual, i) => {
individual.brain = Network(networkArchitecture);
individual.brain.distributeWights(this.ga.population[i]._genome);
return individual;
});
}
async train() {
this.ga.evolve();
}
}
8 changes: 4 additions & 4 deletions src/ai/ga.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ class GeneticAlgorithm {
}
populate(populationSize, problem) {
const { dimentions, min, max } = problem;
this.population = times(
populationSize,
() => new Individual(times(dimentions, () => random(min, max, true))),
);
this.population = times(populationSize, () => {
const genome = times(dimentions, () => random(min, max, true));
return new Individual(genome);
});
}
evolve() {
//calculate fitness before this
Expand Down
18 changes: 9 additions & 9 deletions src/prefabs/player/InputManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ class InputManager {
* Creates an instance of InputManager
* @param {Player} player - The Player to which this InputManager belongs
*/
constructor(player) {
constructor(player, brain) {
this.player = player;
this.brain = brain;
this.scene = player.scene;
this.cursors = player.scene.input.keyboard.createCursorKeys();
[this._shouldGoUp, this.shouldGoDown] = [0, 0];
}

/**
Expand All @@ -19,6 +21,10 @@ class InputManager {
update() {
const { player } = this;

[this._shouldGoUp, this.shouldGoDown] = this.brain
.forward(this.player.perception)
.map(Math.round);

if (player.isDead) {
return;
}
Expand Down Expand Up @@ -51,7 +57,7 @@ class InputManager {
* @returns {boolean}
*/
get isDuckKeyPressed() {
return this.cursors.down.isDown;
return this._shouldGoDown;
}

/**
Expand All @@ -60,13 +66,7 @@ class InputManager {
* @returns {boolean}
*/
get isJumpKeyPressed() {
return Math.round(Math.random());
// const { activePointer } = this.scene.input;
// return (
// this.cursors.up.isDown ||
// this.cursors.space.isDown ||
// (activePointer.isDown && activePointer.wasTouch)
// );
return this._shouldGoUp;
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/prefabs/player/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ class Player extends Phaser.Physics.Arcade.Sprite {
* @param {number} [x=Player.CONFIG.POS.INITIAL_X] - The horizontal position of this Player in the world
* @param {number} [y=Player.CONFIG.POS.Y] - The vertical position of this Player in the world
*/
constructor(scene, x = Player.CONFIG.POS.INITIAL_X, y = Player.CONFIG.POS.Y) {
constructor(scene, x = Player.CONFIG.POS.INITIAL_X, y = Player.CONFIG.POS.Y, trainingData) {
super(scene, x, y, 'dino', Player.CONFIG.FRAMES.INITIAL);

this.fitness = trainingData._fitness;
this.brain = trainingData.brain;

this.isInitialJump = true;

// Init managers
this.physicsManager = new PhysicsManager(this);
this.inputManager = new InputManager(this);
this.inputManager = new InputManager(this, this.brain);
this.animationManager = new AnimationManager(this);

// Init image
Expand Down Expand Up @@ -121,7 +124,7 @@ class Player extends Phaser.Physics.Arcade.Sprite {
* Set player dead | Handle gameover
*/
die(score) {
// if (!this.isDead) console.log(score);
this.fitness.value = score;
this.setState(Player.CONFIG.STATES.DEAD);
this.animationManager.update();
this.physicsManager.reset();
Expand Down
22 changes: 15 additions & 7 deletions src/scenes/game/GameScene.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import Intro from './Intro';
import Player from '../../prefabs/player/Player';
import Horizon from '../../prefabs/horizon/Horizon';
import isTelegramMode from '../../utils/telegram/isTelegramMode';
import { Trainer } from './../../ai/Trainer';
import { times } from 'lodash';

/**
* Main game scene
Expand Down Expand Up @@ -81,7 +83,11 @@ class GameScene extends Phaser.Scene {
this.ui = new UI(this);
this.intro = new Intro(this.events);

this.players = Array.from(Array(10)).map(() => new Player(this));
const populationSize = 10;
this.trainer = new Trainer(populationSize);
this.players = times(populationSize, i => {
return new Player(this, void 0, void 0, this.trainer.population[i]);
});

this.horizon = new Horizon(this);
this.ground = this.horizon.ground;
Expand Down Expand Up @@ -111,12 +117,12 @@ class GameScene extends Phaser.Scene {

update() {
const obstacle = this.obstacles.getLast(true) || { x: this.players[0].x, y: this.players[0].y };
this._score = Phaser.Math.Distance.Between(
this.players[0].x,
this.players[0].y,
obstacle.x,
obstacle.y,
);
this.players.forEach(player => {
const xDistanceToNextObstacle = obstacle.x - player.x;
const yDistanceToNextObstacle = obstacle.y - player.y;
const gapBetweenObstacles = this.obstacles.getGap;
player.perception = [yDistanceToNextObstacle, xDistanceToNextObstacle];
});
const { gameSize } = this.scale;
const isMobile = gameSize.width === CONFIG.GAME.WIDTH.PORTRAIT;

Expand Down Expand Up @@ -224,6 +230,8 @@ class GameScene extends Phaser.Scene {
* Handle gameover
*/
onGameOver() {
this.trainer.train();
console.log(this.trainer.population[0].genome);
const { width: gameWidth, height: gameHeight } = this.scale.gameSize;

this.isPlaying = false;
Expand Down

0 comments on commit a9ac77c

Please sign in to comment.