Skip to content
This repository has been archived by the owner on Jan 12, 2023. It is now read-only.

Commit

Permalink
feat: predecessors
Browse files Browse the repository at this point in the history
  • Loading branch information
Sciator committed Dec 17, 2020
1 parent 6b393de commit 00f124e
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 37 deletions.
31 changes: 17 additions & 14 deletions ui/src/logic/game/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type GameSettings = {
},
game: {
playerSize: number,
maxGameLength: number,
// maxGameLength: number,
},
map: {
size: number,
Expand Down Expand Up @@ -77,7 +77,7 @@ export type GameState = {
bullets: GameStateBullet[],
/** index of game winner, if -1 game isn't over yet -2 if game is draw */
winner: number,
timeRemaining: number,
// timeRemaining: number,
};

export type SensorPoint = { point: Vector, type: "none" | "unknown" | EGameStateObjectType };
Expand Down Expand Up @@ -125,7 +125,7 @@ export class Game {
},
game: {
playerSize: 10,
maxGameLength: 10_000,
// maxGameLength: 10_000,
},
simulation: {
delta: 32,
Expand All @@ -142,11 +142,14 @@ export class Game {
this.applyInput(userInput);

const delta = deltaOveride || deltaSettings;
this.gameState.timeRemaining -= delta;
// this.gameState.timeRemaining -= delta;

// if (this.gameState.timeRemaining <= 0) {
// players.forEach(x => x.health = 0);
// }

players.forEach(x => { x.health -= .002; });

if (this.gameState.timeRemaining <= 0) {
players.forEach(x => x.health = 0);
}

Engine.update(engine, delta);

Expand Down Expand Up @@ -176,11 +179,9 @@ export class Game {
let vec = Vector.rotate(Vector.create(1, 0), body.angle);
vec = Vector.mult(vec, 5);
Body.setVelocity(body, vec);
player.health -= .0005;
}
if (x.rotate !== 0) {
Body.setAngularVelocity(body, x.rotate * .3);
player.health -= Math.abs(x.rotate) * .005;
}
if (x.use) {
this.use(player);
Expand All @@ -206,9 +207,10 @@ export class Game {
World.remove(world, x.p.body);
});

if (alivePlayers.length === 1) {
if (alivePlayers.length === 1 && alivePlayers[0].p.health >= .05) {
this.gameState.winner = alivePlayers[0].i;
} else if (alivePlayers.length === 0) {
deadPlayers.forEach(x => x.p.health = 0);
this.gameState.winner = -2;
}
}
Expand Down Expand Up @@ -237,8 +239,8 @@ export class Game {
const { body: { position, angle }, item } = player;
const { gameState: { bullets }, settings: { game: { playerSize } } } = this;

if (item.cooldown !== 0){
player.health -= .2;
if (item.cooldown !== 0) {
// player.health -= .2;
return;
}
item.cooldown = itemCooldown;
Expand All @@ -260,6 +262,7 @@ export class Game {
health: 1,
body,
});
// player.health -= .1;
}

// todo: move all sensor related things into GameAI folder
Expand Down Expand Up @@ -331,7 +334,7 @@ export class Game {
World.add(world, players);

this.gameState = {
walls: walls.map(x=>({body:x, health:Infinity, type:EGameStateObjectType.wall})),
walls: walls.map(x => ({ body: x, health: Infinity, type: EGameStateObjectType.wall })),
players: players.map((body) =>
({
type: EGameStateObjectType.player,
Expand All @@ -342,7 +345,7 @@ export class Game {
),
bullets: [],
winner: -1,
timeRemaining: settings.game.maxGameLength,
// timeRemaining: settings.game.maxGameLength,
};

Events.on(this.engine, "collisionStart", this.onCollision.bind(this));
Expand Down
14 changes: 9 additions & 5 deletions ui/src/logic/gameAi/GameAiEval.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Vector } from "matter-js";
import { IANNInitParams, NeuralNet } from "../ai/nn/nn";
import { EGameStateObjectType, Game, GameInputPlayer, GameSettings, SensorPoint } from "../game/game";
import { EGameStateObjectType, Game, GameInputPlayer, GameSettings, GameState, SensorPoint } from "../game/game";


export type InitializeRandomBotParams = {
Expand Down Expand Up @@ -53,7 +53,9 @@ export class GameAiEval {
public static NN_OUTPUTS = 4;
/** returns number of nn inputs for given sensors array */
public static NN_INPUTS_GET({ sensors }: { sensors: number[] | { length: number } }) {
return (sensors.length * 2 + 1) * 2;
return (sensors.length * 2 + 1) * 2
// health + cooldown
+ 2;
}

public static initializeRandomBot(params: InitializeRandomBotParams): NeuralNet {
Expand All @@ -65,9 +67,9 @@ export class GameAiEval {
});
}

private sensorAsNumbers(playerIndex: number, points: SensorPoint[]): number[] {
private botInputs(playerIndex: number, points: SensorPoint[]): number[] {
const { gameState: { players } } = this.game;
const { body: { position } } = players[playerIndex];
const { body: { position }, health, item: { cooldown } } = players[playerIndex];

const numbers: number[] = [];

Expand All @@ -76,6 +78,8 @@ export class GameAiEval {
numbers.push(dist(point, position), numFromType(type));
}

numbers.push(health, cooldown);

return numbers;
}

Expand All @@ -100,7 +104,7 @@ export class GameAiEval {
public calculateBotResponse() {
const { game } = this;
const { gameState: { players } } = this.game;
const sensorsResults = players.map((_, i) => this.sensorAsNumbers(i, game.sensor(i)));
const sensorsResults = players.map((_, i) => this.botInputs(i, game.sensor(i)));
const botsNNResults = sensorsResults.map((x, i) => this.playerNNs[i].predict(x));
const botsActions = botsNNResults.map(x => this.inputFromNN(x));

Expand Down
33 changes: 23 additions & 10 deletions ui/src/logic/gameAi/GameAiLiveTrain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export type Bot = {
wins: number,
lastGame: number,
nn: NeuralNet,
children: number,
predecessors: number[],
};


Expand All @@ -26,7 +28,7 @@ export class GameAiLiveTrain {
/** for how many games has bot healths */
healthMultiplier: 4,
/** how many hp will player get after game when survives */
healthGrowAfterGame: .2,
healthGrowAfterGame: 1.4,
sensors: [Math.PI * 1 / 4, Math.PI * 1 / 8, Math.PI * 1 / 32],
};

Expand All @@ -36,7 +38,9 @@ export class GameAiLiveTrain {
const bots = this.bots;

const selectedIndex: number[] = math.pickRandom(
range(bots.length), 2, bots.map(x => Math.max(1, (x.lastGame - 1000) ** 3 - x.games + x.bonus + x.wins ** 2))
range(bots.length), 2, bots.map(x => Math.max(1,
((1 - x.health) * 10) ** 2 + x.lastGame - x.games - x.bonus + (x.wins) ** 2
))
) as any;

const selected = selectedIndex.map(x => bots[x]);
Expand Down Expand Up @@ -75,10 +79,9 @@ export class GameAiLiveTrain {
const resHealth = evaler.game.gameState.players.map(x => x.health);
resHealth.forEach((x, i) => {
const bot = selected[i];
bot.health += x / healthMultiplier;
if (x > 0) bot.health += healthGrowAfterGame/healthMultiplier;
bot.health += healthGrowAfterGame * x / healthMultiplier;

const exceedingHealth = (bot.health - healthMultiplier)*healthMultiplier;
const exceedingHealth = (bot.health - healthMultiplier) * healthMultiplier;
if (exceedingHealth > 0) {
bot.health = this.params.healthMultiplier;
const bonusMultiplier =
Expand All @@ -101,8 +104,14 @@ export class GameAiLiveTrain {

selected.forEach(x => { x.lastGame = 0; x.games++; });

if (populationToMaxFrac > .9) {
bots.map(x => x.bonus += .05);
if (populationToMaxFrac > .75) {
bots.forEach(x => {
x.bonus = Math.min(x.bonus * 5 + populationToMaxFrac, 2)
});
};

if (populationToMaxFrac > .8) {
bots.map(x => x.bonus += .01 * populationToMaxFrac);
}

if (bots.length < 10)
Expand All @@ -124,9 +133,11 @@ export class GameAiLiveTrain {
const bot = bots[i];
if (bot.bonus < 1) continue;

const ci = bot.children++;
const predecessors = bot.predecessors.concat(ci);
console.log("new bot created");
bot.bonus--;
bots.push({ bonus: 0, games: 0, wins: 0, health: this.params.healthMultiplier, lastGame: 0, nn: bot.nn.mutate(.01) });
bots.push({ bonus: 0, games: 0, wins: 0, health: 1, lastGame: 0, nn: bot.nn.mutate(.01), children: 0, predecessors });
}
}

Expand All @@ -136,13 +147,15 @@ export class GameAiLiveTrain {
const { hiddens } = constructorParams;
const { sensors } = params;

this.bots = range(params.maxPop).map(() => ({
this.bots = range(params.maxPop).map((i) => ({
bonus: 0,
health: params.healthMultiplier,
health: 1,
games: 0,
wins: 0,
lastGame: 0,
nn: GameAiEval.initializeRandomBot({ hiddens, sensors }),
children: 0,
predecessors: [i],
}));
}
}
Expand Down
6 changes: 4 additions & 2 deletions ui/src/views/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Card, Row, Col } from "antd";
import React, { useState } from "react";
import React, { useCallback, useState } from "react";
import { PlayPage } from "./Play";
import { RunAI } from "./RunAI";
import { NeuralNet } from "../logic/ai/nn/nn";
Expand All @@ -19,6 +19,8 @@ export const MainPage: React.FC<TMainPageProps> = () => {
// const [aiSettings, setAiSettings] = useState<TSettingState>(defaultInitParams as any);
const [snapshot, setSnapshot] = useState<NeuralNet[] | undefined>(undefined);

const callback = useCallback((e: NeuralNet[]) => setSnapshot(e), []);

return <>
<Card>
<Row gutter={[8, 0]}>
Expand All @@ -29,7 +31,7 @@ export const MainPage: React.FC<TMainPageProps> = () => {
{/* <Col sm={8}> */}
<Row gutter={[8, 8]}>
<Col sm={8}>
<RunAI onSnapshot={(e) => setSnapshot(e)} />
<RunAI onSnapshot={callback} />
</Col>
<Col sm={16}>
<PlayPage snapshot={snapshot} />
Expand Down
20 changes: 14 additions & 6 deletions ui/src/views/RunAI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const targetDeltaTime = 1_000 / fps;

type BotSnapshot = { bots: Bot[], popsize: number };
const createBotSnapshot = (bots: Bot[], samples: number): BotSnapshot => {
return { bots: bots.slice(0, samples).map(x => ({ ...x })), popsize: bots.length };
return { bots: bots.slice(0, samples).map(x => ({ ...x, predecessors: x.predecessors.slice() })), popsize: bots.length };
};


Expand All @@ -28,11 +28,14 @@ const BotData = ({ popsize, bots, calculations }: BotSnapshot & { calculations:
</Row>
<Row gutter={[0, 12]}>
{
bots.map(({ bonus, games, health, lastGame, wins }) => {
bots.map(({ bonus, games, health, lastGame, wins, children, predecessors }) => {
return <Col sm={24}>
<Card>
<Row>
<Col sm={18}>
<Row>
{predecessors.map(x => x.toString(16).padStart(4, "0")).join("-")}
</Row>
<Row>
<Progress percent={bonus * 100} status={"active"} strokeColor={"#f4f711"} format={() => ""}></Progress>
</Row>
Expand All @@ -43,13 +46,16 @@ const BotData = ({ popsize, bots, calculations }: BotSnapshot & { calculations:
<Col sm={6}>
<Row>
{games.toLocaleString().padStart(5, " ")} : Games
</Row>
</Row>
<Row>
{wins.toLocaleString().padStart(5, " ")} : Wins
</Row>
</Row>
<Row>
{children.toLocaleString().padStart(5, " ")} : children
</Row>
<Row>
{lastGame.toLocaleString().padStart(5, " ")} : last
</Row>
</Row>
</Col>
</Row>
</Card>
Expand All @@ -68,6 +74,8 @@ const fakeSnapshot: BotSnapshot = {
games: randInt(1000),
lastGame: randInt(1000),
nn: undefined as any,
children: randInt(1000),
predecessors: range(randInt(1, 5)).map(() => randInt(100)),
})), popsize: 100,
};

Expand Down Expand Up @@ -108,7 +116,7 @@ export const RunAI: React.FC<TRunProps> = ({ onSnapshot }) => {

setTimeout(() => {
setLastUpdate(Date.now());
});
}, 15);
}, [lastUpdate, setLastUpdate, running, onSnapshot]);


Expand Down

0 comments on commit 00f124e

Please sign in to comment.