Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bleckert/football-simulator

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bleckert/football-simulator - npm Package Compare versions

Comparing version 0.0.5 to 0.0.6

128

Commentator.js

@@ -1,39 +0,37 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Event_1 = require("./enums/Event");
var importantEvents = [
Event_1.Event.GameStart,
Event_1.Event.Kickoff,
Event_1.Event.HalfTime,
Event_1.Event.Advance,
Event_1.Event.Save,
Event_1.Event.Block,
Event_1.Event.Goal,
Event_1.Event.GameEnd,
Event_1.Event.Injury,
import { Event } from './enums/Event';
const importantEvents = [
Event.GameStart,
Event.Kickoff,
Event.HalfTime,
Event.Advance,
Event.Save,
Event.Block,
Event.Goal,
Event.GameEnd,
Event.Injury,
];
var Commentator = /** @class */ (function () {
function Commentator(name) {
if (name === void 0) { name = 'Mr. Commentator'; }
export default class Commentator {
name;
constructor(name = 'Mr. Commentator') {
this.name = name;
}
Commentator.prototype.routeComment = function (event) {
routeComment(event) {
switch (event.event) {
case Event_1.Event.GameStart:
case Event.GameStart:
return this.gameStarted(event);
case Event_1.Event.Kickoff:
case Event.Kickoff:
return this.kickoff(event);
case Event_1.Event.HalfTime:
case Event.HalfTime:
return this.halfTime(event);
case Event_1.Event.Advance:
case Event.Advance:
return this.advance(event);
case Event_1.Event.Defence:
case Event.Defence:
return this.defence(event);
case Event_1.Event.Save:
case Event.Save:
return this.save(event);
case Event_1.Event.Block:
case Event.Block:
return this.block(event);
case Event_1.Event.Goal:
case Event.Goal:
return this.goal(event);
case Event_1.Event.GameEnd:
case Event.GameEnd:
return this.gameEnded(event);

@@ -43,5 +41,5 @@ default:

}
};
Commentator.prototype.comment = function (event) {
var importantEvent = event.event in importantEvents;
}
comment(event) {
const importantEvent = event.event in importantEvents;
if (!importantEvent && Math.random() > 0.5) {

@@ -51,44 +49,42 @@ return null;

return this.routeComment(event);
};
Commentator.prototype.gameStarted = function (event) {
return "The game between " + event.homeTeam.name + " and " + event.awayTeam.name + " has started.";
};
Commentator.prototype.kickoff = function (event) {
return event.data.name + " with the kickoff.";
};
Commentator.prototype.halfTime = function (event) {
return "It's half time! The score is " + event.gameInfo.homeGoals + " - " + event.gameInfo.awayGoals;
};
Commentator.prototype.advance = function (event) {
return event.attackingTeam.name + " advances with the ball.";
};
Commentator.prototype.defence = function (event) {
return event.defendingTeam.name + " tries to advance but good defence by " + event.attackingTeam.name + " that steals the ball.";
};
Commentator.prototype.rebound = function (comment, event) {
}
gameStarted(event) {
return `The game between ${event.homeTeam.name} and ${event.awayTeam.name} has started.`;
}
kickoff(event) {
return `${event.data.name} with the kickoff.`;
}
halfTime(event) {
return `It's half time! The score is ${event.gameInfo.homeGoals} - ${event.gameInfo.awayGoals}`;
}
advance(event) {
return `${event.attackingTeam.name} advances with the ball.`;
}
defence(event) {
return `${event.defendingTeam.name} tries to advance but good defence by ${event.attackingTeam.name} that steals the ball.`;
}
rebound(comment, event) {
if (event.data === event.attackingTeam) {
return event.attackingTeam.name + " gets the ball back.";
return `${event.attackingTeam.name} gets the ball back.`;
}
return [comment, event.attackingTeam.name + " can take control over the ball."].join(' ');
};
Commentator.prototype.save = function (event) {
return this.rebound(event.attackingPrimaryPlayer.info.name + " tries to score but the goalkeeper saves the ball.", event);
};
Commentator.prototype.block = function (event) {
return this.rebound(event.attackingPrimaryPlayer.info.name + " tries to score but the ball was blocked by the defence.", event);
};
Commentator.prototype.goal = function (event) {
return event.attackingPrimaryPlayer.info.name + " shoots and he scores! " + event.gameInfo.homeGoals + "-" + event.gameInfo.awayGoals;
};
Commentator.prototype.gameEnded = function (event) {
return [comment, `${event.attackingTeam.name} can take control over the ball.`].join(' ');
}
save(event) {
return this.rebound(`${event.attackingPrimaryPlayer.info.name} tries to score but the goalkeeper saves the ball.`, event);
}
block(event) {
return this.rebound(`${event.attackingPrimaryPlayer.info.name} tries to score but the ball was blocked by the defence.`, event);
}
goal(event) {
return `${event.attackingPrimaryPlayer.info.name} shoots and he scores! ${event.gameInfo.homeGoals}-${event.gameInfo.awayGoals}`;
}
gameEnded(event) {
if (event.gameInfo.homeGoals > event.gameInfo.awayGoals) {
return "The game has ended! " + event.homeTeam.name + " wins " + event.gameInfo.homeGoals + "-" + event.gameInfo.awayGoals;
return `The game has ended! ${event.homeTeam.name} wins ${event.gameInfo.homeGoals}-${event.gameInfo.awayGoals}`;
}
if (event.gameInfo.homeGoals < event.gameInfo.awayGoals) {
return "The game has ended! " + event.awayTeam.name + " takes 3 points on the road! " + event.gameInfo.homeGoals + "-" + event.gameInfo.awayGoals;
return `The game has ended! ${event.awayTeam.name} takes 3 points on the road! ${event.gameInfo.homeGoals}-${event.gameInfo.awayGoals}`;
}
return "The game ends with a draw! Final score " + event.gameInfo.homeGoals + "-" + event.gameInfo.awayGoals;
};
return Commentator;
}());
exports.default = Commentator;
return `The game ends with a draw! Final score ${event.gameInfo.homeGoals}-${event.gameInfo.awayGoals}`;
}
}

@@ -1,100 +0,74 @@

"use strict";
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
var Event_1 = require("./enums/Event");
var FieldArea_1 = require("./enums/FieldArea");
var Action_1 = require("./enums/Action");
var GoalType_1 = require("./enums/GoalType");
var AssistType_1 = require("./enums/AssistType");
var Engine = /** @class */ (function () {
function Engine(homeTeam, awayTeam) {
var _this = this;
/**
* Has the game started?
*/
this.gameStarted = false;
/**
* Has the game ended?
*/
this.gameEnded = false;
/**
* Number of minutes for a full game
*/
this.gameTime = 90;
/**
* Number of events per minutes. This decides how eventful the game should be,
* how many actions can take place within a minute.
*/
this.eventsPerMinute = 1;
/**
* Extra rating points for home team attributes
*/
this.homeTeamAdvantage = 2;
/**
* All attributes are randomized on each simulation using
* a positive or negative version of this value
*/
this.randomEffect = 25;
/**
* Chance (0 to 1) to get the ball back after goal attempt.
*/
this.reboundChance = 0.1;
/**
* Increase attack attributes on goal chance
*/
this.extraAttackOnChance = 0.05;
/**
* Current team with possession.
*/
this.ballPossession = null;
/**
* The team that started with the ball.
*/
this.startedWithBall = null;
/**
* FieldArea enum describing the current ball position.
*/
this.ballPosition = FieldArea_1.FieldArea.Midfield;
/**
* Array containing all simulations
*/
this.gameEvents = [];
this.simulate = function () {
if (!_this.gameStarted) {
_this.start();
}
var event = _this.gameLoop.next();
if (event.done) {
return;
}
_this.gameEvents.push(event.value);
_this.handleEvent(event.value);
_this.simulate();
};
import { Event } from './enums/Event';
import { FieldArea } from "./enums/FieldArea";
import { Action } from './enums/Action';
import { GoalType } from "./enums/GoalType";
import { AssistType } from "./enums/AssistType";
export default class Engine {
/**
* Has the game started?
*/
gameStarted = false;
/**
* Has the game ended?
*/
gameEnded = false;
/**
* Number of minutes for a full game
*/
gameTime = 90;
/**
* Number of events per minutes. This decides how eventful the game should be,
* how many actions can take place within a minute.
*/
eventsPerMinute = 1;
/**
* Extra rating points for home team attributes
*/
homeTeamAdvantage = 2;
/**
* All attributes are randomized on each simulation using
* a positive or negative version of this value
*/
randomEffect = 25;
/**
* Chance (0 to 1) to get the ball back after goal attempt.
*/
reboundChance = 0.1;
/**
* Increase attack attributes on goal chance
*/
extraAttackOnChance = 0.05;
/**
* Current team with possession.
*/
ballPossession = null;
/**
* The team that started with the ball.
*/
startedWithBall = null;
/**
* FieldArea enum describing the current ball position.
*/
ballPosition = FieldArea.Midfield;
/**
* Game info object describing the current state of the game
*/
gameInfo;
/**
* Array containing all simulations
*/
gameEvents = [];
/**
* The game loop
*/
gameLoop;
/**
* The home team
*/
homeTeam;
/**
* The away team
*/
awayTeam;
constructor(homeTeam, awayTeam) {
this.homeTeam = homeTeam;

@@ -109,45 +83,56 @@ this.awayTeam = awayTeam;

}
Engine.prototype.start = function () {
var coinflip = Math.floor(Math.random() * 2) == 0;
start() {
const coinflip = Math.floor(Math.random() * 2) == 0;
this.ballPossession = (coinflip) ? this.homeTeam : this.awayTeam;
this.startedWithBall = this.ballPossession;
this.gameEvents.push(this.gameEvent(Event_1.Event.GameStart, this.ballPossession));
this.gameEvents.push(this.gameEvent(Event_1.Event.Kickoff, this.ballPossession));
this.gameEvents.push(this.gameEvent(Event.GameStart, this.ballPossession));
this.gameEvents.push(this.gameEvent(Event.Kickoff, this.ballPossession));
this.gameStarted = true;
};
Engine.prototype.teamWithoutBall = function () {
}
teamWithoutBall() {
return (this.ballPossession === this.homeTeam) ? this.awayTeam : this.homeTeam;
}
simulate = () => {
if (!this.gameStarted) {
this.start();
}
const event = this.gameLoop.next();
if (event.done) {
return;
}
this.gameEvents.push(event.value);
this.handleEvent(event.value);
this.simulate();
};
Engine.prototype.rebound = function () {
rebound() {
return Math.floor(Math.random()) > this.reboundChance;
};
Engine.prototype.reverseSide = function (current) {
var _a;
var map = (_a = {},
_a[FieldArea_1.FieldArea.Offense] = FieldArea_1.FieldArea.Defence,
_a[FieldArea_1.FieldArea.Midfield] = FieldArea_1.FieldArea.Midfield,
_a[FieldArea_1.FieldArea.Defence] = FieldArea_1.FieldArea.Offense,
_a);
}
reverseSide(current) {
const map = {
[FieldArea.Offense]: FieldArea.Defence,
[FieldArea.Midfield]: FieldArea.Midfield,
[FieldArea.Defence]: FieldArea.Offense,
};
return map[current];
};
Engine.prototype.handleEvent = function (event) {
}
handleEvent(event) {
switch (event.event) {
case Event_1.Event.Goal:
this.ballPosition = FieldArea_1.FieldArea.Midfield;
case Event.Goal:
this.ballPosition = FieldArea.Midfield;
this.ballPossession = this.teamWithoutBall();
break;
case Event_1.Event.Save:
case Event_1.Event.Block:
case Event.Save:
case Event.Block:
if (!this.rebound()) {
this.ballPossession = this.teamWithoutBall();
this.ballPosition = FieldArea_1.FieldArea.Defence;
this.ballPosition = FieldArea.Defence;
}
break;
case Event_1.Event.Advance:
this.ballPosition = Math.min(this.ballPosition + 1, FieldArea_1.FieldArea.Offense);
case Event.Advance:
this.ballPosition = Math.min(this.ballPosition + 1, FieldArea.Offense);
break;
case Event_1.Event.Retreat:
this.ballPosition = Math.max(this.ballPosition - 1, FieldArea_1.FieldArea.Defence);
case Event.Retreat:
this.ballPosition = Math.max(this.ballPosition - 1, FieldArea.Defence);
break;
case Event_1.Event.Defence:
case Event.Defence:
this.ballPossession = this.teamWithoutBall();

@@ -157,37 +142,16 @@ this.ballPosition = this.reverseSide(this.ballPosition);

}
};
Engine.prototype.eventLoop = function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this.gameInfo.matchMinute;
_a.label = 1;
case 1:
if (!(this.gameInfo.matchMinute <= this.gameTime)) return [3 /*break*/, 4];
return [4 /*yield*/, this.simulateEvent()];
case 2:
_a.sent();
_a.label = 3;
case 3:
this.gameInfo.matchMinute += 1 / this.eventsPerMinute;
return [3 /*break*/, 1];
case 4: return [2 /*return*/];
}
});
};
Engine.prototype.gameEvent = function (event, data, attackingPrimaryPlayer, attackingSecondaryPlayer, defendingPrimaryPlayer, defendingSecondaryPlayer, goalType, assistType) {
if (data === void 0) { data = null; }
if (attackingPrimaryPlayer === void 0) { attackingPrimaryPlayer = null; }
if (attackingSecondaryPlayer === void 0) { attackingSecondaryPlayer = null; }
if (defendingPrimaryPlayer === void 0) { defendingPrimaryPlayer = null; }
if (defendingSecondaryPlayer === void 0) { defendingSecondaryPlayer = null; }
if (goalType === void 0) { goalType = null; }
if (assistType === void 0) { assistType = null; }
}
*eventLoop() {
for (this.gameInfo.matchMinute; this.gameInfo.matchMinute <= this.gameTime; this.gameInfo.matchMinute += 1 / this.eventsPerMinute) {
yield this.simulateEvent();
}
}
gameEvent(event, data = null, attackingPrimaryPlayer = null, attackingSecondaryPlayer = null, defendingPrimaryPlayer = null, defendingSecondaryPlayer = null, goalType = null, assistType = null) {
return {
event: event,
data: data,
attackingPrimaryPlayer: attackingPrimaryPlayer,
attackingSecondaryPlayer: attackingSecondaryPlayer,
defendingPrimaryPlayer: defendingPrimaryPlayer,
defendingSecondaryPlayer: defendingSecondaryPlayer,
event,
data,
attackingPrimaryPlayer,
attackingSecondaryPlayer,
defendingPrimaryPlayer,
defendingSecondaryPlayer,
gameInfo: Object.assign({}, this.gameInfo),

@@ -199,10 +163,10 @@ homeTeam: this.homeTeam,

fieldPosition: this.ballPosition,
goalType: goalType,
assistType: assistType,
goalType,
assistType,
};
};
Engine.prototype.random = function (team) {
var min = -this.randomEffect;
var max = this.randomEffect;
var random = Math.floor(Math.random() * (max - min + 1) + min);
}
random(team) {
const min = -this.randomEffect;
const max = this.randomEffect;
let random = Math.floor(Math.random() * (max - min + 1) + min);
if (team === this.homeTeam) {

@@ -212,74 +176,74 @@ random += this.homeTeamAdvantage;

return random;
};
Engine.prototype.simulateGoalAttempt = function (attackingTeam, defendingTeam, attacker) {
var defence = defendingTeam.defenceRating() + this.random(defendingTeam);
var attack = attackingTeam.attackRating() + this.random(attackingTeam);
}
simulateGoalAttempt(attackingTeam, defendingTeam, attacker) {
const defence = defendingTeam.defenceRating() + this.random(defendingTeam);
const attack = attackingTeam.attackRating() + this.random(attackingTeam);
if (attack + (attack * this.extraAttackOnChance) > defence) {
var goalkeeper = defendingTeam.goalkeeperRating() + this.random(defendingTeam);
var attackerRating = attacker.attackRating() + this.random(attackingTeam);
return (attackerRating > goalkeeper) ? Event_1.Event.Goal : Event_1.Event.Save;
const goalkeeper = defendingTeam.goalkeeperRating() + this.random(defendingTeam);
const attackerRating = attacker.attackRating() + this.random(attackingTeam);
return (attackerRating > goalkeeper) ? Event.Goal : Event.Save;
}
return Event_1.Event.Block;
};
Engine.prototype.simulatePossession = function (attackingTeam, defendingTeam, action) {
var defence = defendingTeam.defenceRating() + this.random(defendingTeam);
var possession = attackingTeam.possessionRating() + this.random(attackingTeam);
return Event.Block;
}
simulatePossession(attackingTeam, defendingTeam, action) {
const defence = defendingTeam.defenceRating() + this.random(defendingTeam);
const possession = attackingTeam.possessionRating() + this.random(attackingTeam);
if (defence > possession) {
return Event_1.Event.Defence;
return Event.Defence;
}
return (action === Action_1.Action.Retreat) ? Event_1.Event.Retreat : Event_1.Event.Possession;
};
Engine.prototype.simulateAction = function (action, attacker) {
return (action === Action.Retreat) ? Event.Retreat : Event.Possession;
}
simulateAction(action, attacker) {
if (!this.ballPossession) {
return Event_1.Event.EventLess;
return Event.EventLess;
}
var attackingTeam = this.ballPossession;
var defendingTeam = this.teamWithoutBall();
var defence = defendingTeam.defenceRating() + this.random(defendingTeam);
var attack = attackingTeam.attackRating() + this.random(attackingTeam);
if (action === Action_1.Action.Advance) {
return (attack > defence) ? Event_1.Event.Advance : Event_1.Event.Defence;
const attackingTeam = this.ballPossession;
const defendingTeam = this.teamWithoutBall();
const defence = defendingTeam.defenceRating() + this.random(defendingTeam);
const attack = attackingTeam.attackRating() + this.random(attackingTeam);
if (action === Action.Advance) {
return (attack > defence) ? Event.Advance : Event.Defence;
}
if (action === Action_1.Action.GoalAttempt) {
if (action === Action.GoalAttempt) {
return this.simulateGoalAttempt(attackingTeam, defendingTeam, attacker);
}
return this.simulatePossession(attackingTeam, defendingTeam, action);
};
Engine.prototype.simulateAssistType = function (secondaryPlayer) {
var random = Math.random();
var secondaryPlayerAttributes = secondaryPlayer.attributes;
var secondaryPlayerRating = secondaryPlayer.rating();
var shooting = secondaryPlayerRating.shooting;
var passing = secondaryPlayerRating.passing;
}
simulateAssistType(secondaryPlayer) {
const random = Math.random();
const secondaryPlayerAttributes = secondaryPlayer.attributes;
const secondaryPlayerRating = secondaryPlayer.rating();
const shooting = secondaryPlayerRating.shooting;
const passing = secondaryPlayerRating.passing;
if (shooting > passing && random > 0.5) {
return (random > 0.5) ? AssistType_1.AssistType.Deflection : AssistType_1.AssistType.Rebound;
return (random > 0.5) ? AssistType.Deflection : AssistType.Rebound;
}
if (secondaryPlayerAttributes.passing > secondaryPlayerAttributes.crossing && random > 0.5) {
return AssistType_1.AssistType.Pass;
return AssistType.Pass;
}
return AssistType_1.AssistType.Cross;
};
Engine.prototype.simulateGoalType = function (primaryPlayer, secondaryPlayer) {
var assist = Math.random() > 0.5;
return AssistType.Cross;
}
simulateGoalType(primaryPlayer, secondaryPlayer) {
const assist = Math.random() > 0.5;
if (!assist) {
return [GoalType_1.GoalType.Shot, null];
return [GoalType.Shot, null];
}
var primaryPlayerAttributes = primaryPlayer.attributes;
var random = Math.random();
var assistType = this.simulateAssistType(secondaryPlayer);
const primaryPlayerAttributes = primaryPlayer.attributes;
const random = Math.random();
const assistType = this.simulateAssistType(secondaryPlayer);
return [
(primaryPlayerAttributes.heading > primaryPlayerAttributes.finishing && random > 0.5) ? GoalType_1.GoalType.Header : [GoalType_1.GoalType.Volley, GoalType_1.GoalType.Shot][Math.floor(Math.random() * 2)],
(primaryPlayerAttributes.heading > primaryPlayerAttributes.finishing && random > 0.5) ? GoalType.Header : [GoalType.Volley, GoalType.Shot][Math.floor(Math.random() * 2)],
assistType,
];
};
Engine.prototype.halfTime = function () {
}
halfTime() {
this.ballPossession = this.startedWithBall === this.homeTeam ? this.awayTeam : this.homeTeam;
this.ballPosition = FieldArea_1.FieldArea.Midfield;
return this.gameEvent(Event_1.Event.HalfTime);
};
Engine.prototype.gameEnd = function () {
this.ballPosition = FieldArea.Midfield;
return this.gameEvent(Event.HalfTime);
}
gameEnd() {
this.gameEnded = true;
return this.gameEvent(Event_1.Event.GameEnd);
};
Engine.prototype.goal = function (attackingPrimaryPlayer, attackingSecondaryPlayer) {
return this.gameEvent(Event.GameEnd);
}
goal(attackingPrimaryPlayer, attackingSecondaryPlayer) {
if (this.ballPossession === this.homeTeam) {

@@ -292,5 +256,4 @@ this.gameInfo.homeGoals += 1;

return this.simulateGoalType(attackingPrimaryPlayer, attackingSecondaryPlayer);
};
Engine.prototype.simulateEvent = function () {
var _a;
}
simulateEvent() {
if (this.gameInfo.matchMinute == this.gameTime / 2)

@@ -301,18 +264,16 @@ return this.halfTime();

if (!this.ballPossession)
return this.gameEvent(Event_1.Event.EventLess);
var attackingPrimaryPlayer = this.ballPossession.attacker(this.ballPosition);
var attackingSecondaryPlayer = this.ballPossession.attacker(this.ballPosition, [attackingPrimaryPlayer]);
var defendingTeam = this.teamWithoutBall();
var defendingPrimaryPlayer = defendingTeam.defender(this.ballPosition);
var action = this.ballPossession.simulateMove(this.ballPosition, this.gameInfo);
var goalType = null;
var assist = null;
var event = this.simulateAction(action, attackingPrimaryPlayer);
if (event === Event_1.Event.Goal) {
_a = this.goal(attackingPrimaryPlayer, attackingSecondaryPlayer), goalType = _a[0], assist = _a[1];
return this.gameEvent(Event.EventLess);
const attackingPrimaryPlayer = this.ballPossession.attacker(this.ballPosition);
const attackingSecondaryPlayer = this.ballPossession.attacker(this.ballPosition, [attackingPrimaryPlayer]);
const defendingTeam = this.teamWithoutBall();
const defendingPrimaryPlayer = defendingTeam.defender(this.ballPosition);
const action = this.ballPossession.simulateMove(this.ballPosition, this.gameInfo);
let goalType = null;
let assist = null;
const event = this.simulateAction(action, attackingPrimaryPlayer);
if (event === Event.Goal) {
[goalType, assist] = this.goal(attackingPrimaryPlayer, attackingSecondaryPlayer);
}
return this.gameEvent(event, null, attackingPrimaryPlayer, attackingSecondaryPlayer, defendingPrimaryPlayer, defendingTeam.defender(this.ballPosition, [defendingPrimaryPlayer]), goalType, assist);
};
return Engine;
}());
exports.default = Engine;
}
}

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Action = void 0;
var Action;
export var Action;
(function (Action) {

@@ -10,2 +7,2 @@ Action[Action["Advance"] = 0] = "Advance";

Action[Action["GoalAttempt"] = 3] = "GoalAttempt";
})(Action = exports.Action || (exports.Action = {}));
})(Action || (Action = {}));

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssistType = void 0;
var AssistType;
export var AssistType;
(function (AssistType) {

@@ -10,2 +7,2 @@ AssistType[AssistType["Pass"] = 0] = "Pass";

AssistType[AssistType["Deflection"] = 3] = "Deflection";
})(AssistType = exports.AssistType || (exports.AssistType = {}));
})(AssistType || (AssistType = {}));

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefenceType = void 0;
var DefenceType;
export var DefenceType;
(function (DefenceType) {

@@ -9,2 +6,2 @@ DefenceType[DefenceType["SlideTackle"] = 0] = "SlideTackle";

DefenceType[DefenceType["AirDuel"] = 2] = "AirDuel";
})(DefenceType = exports.DefenceType || (exports.DefenceType = {}));
})(DefenceType || (DefenceType = {}));

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Event = void 0;
var Event;
export var Event;
(function (Event) {

@@ -22,2 +19,2 @@ Event[Event["GameStart"] = 0] = "GameStart";

Event[Event["FreeKick"] = 15] = "FreeKick";
})(Event = exports.Event || (exports.Event = {}));
})(Event || (Event = {}));

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FieldArea = void 0;
var FieldArea;
export var FieldArea;
(function (FieldArea) {

@@ -9,2 +6,2 @@ FieldArea[FieldArea["Defence"] = 0] = "Defence";

FieldArea[FieldArea["Offense"] = 2] = "Offense";
})(FieldArea = exports.FieldArea || (exports.FieldArea = {}));
})(FieldArea || (FieldArea = {}));

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GoalType = void 0;
var GoalType;
export var GoalType;
(function (GoalType) {

@@ -9,2 +6,2 @@ GoalType[GoalType["Shot"] = 0] = "Shot";

GoalType[GoalType["Header"] = 2] = "Header";
})(GoalType = exports.GoalType || (exports.GoalType = {}));
})(GoalType || (GoalType = {}));

@@ -1,5 +0,2 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.attackPositions = exports.midfieldPositions = exports.defencePositions = exports.Position = void 0;
var Position;
export var Position;
(function (Position) {

@@ -31,4 +28,4 @@ Position[Position["GK"] = 0] = "GK";

Position[Position["ST"] = 24] = "ST";
})(Position = exports.Position || (exports.Position = {}));
exports.defencePositions = [
})(Position || (Position = {}));
export const defencePositions = [
Position.LB,

@@ -41,3 +38,3 @@ Position.LCB,

];
exports.midfieldPositions = [
export const midfieldPositions = [
Position.LDM,

@@ -53,3 +50,3 @@ Position.DM,

];
exports.attackPositions = [
export const attackPositions = [
Position.LW,

@@ -56,0 +53,0 @@ Position.LCOM,

@@ -1,60 +0,43 @@

"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = require("events");
var Engine_1 = require("./Engine");
var Reporter_1 = require("./Reporter");
var Game = /** @class */ (function (_super) {
__extends(Game, _super);
function Game(homeTeam, awayTeam, commentator) {
var _this = _super.call(this) || this;
/**
* Milliseconds between each simulation
*/
_this.gameSpeed = 500;
/**
* Events copy
*/
_this.events = [];
_this.loop = function () {
var event = _this.events.shift();
if (!event) {
_this.report();
return;
}
_this.emit('comment', {
text: _this.commentator.comment(event),
gameInfo: event.gameInfo,
});
_this.emit('event', event);
setTimeout(_this.loop, _this.gameSpeed);
};
_this.homeTeam = homeTeam;
_this.awayTeam = awayTeam;
_this.commentator = commentator;
_this.engine = new Engine_1.default(_this.homeTeam, _this.awayTeam);
return _this;
import { EventEmitter } from 'events';
import Engine from './Engine';
import Reporter from './Reporter';
export default class Game extends EventEmitter {
/**
* Milliseconds between each simulation
*/
gameSpeed = 500;
/**
* Engine
*/
engine;
/**
* The home team
*/
homeTeam;
/**
* The away team
*/
awayTeam;
/**
* The commentator
*/
commentator;
/**
* Events copy
*/
events = [];
constructor(homeTeam, awayTeam, commentator) {
super();
this.homeTeam = homeTeam;
this.awayTeam = awayTeam;
this.commentator = commentator;
this.engine = new Engine(this.homeTeam, this.awayTeam);
}
Game.prototype.start = function () {
var _this = this;
start() {
this.engine.start();
this.events = this.engine.gameEvents.slice();
this.events.forEach(function (gameEvent) {
_this.emit('comment', {
text: _this.commentator.comment(gameEvent),
gameInfo: _this.engine.gameInfo,
this.events.forEach(gameEvent => {
this.emit('comment', {
text: this.commentator.comment(gameEvent),
gameInfo: this.engine.gameInfo,
});

@@ -65,14 +48,25 @@ });

this.simulate();
};
Game.prototype.simulate = function () {
}
simulate() {
this.engine.simulate();
this.events = this.engine.gameEvents.slice();
this.loop();
}
loop = () => {
const event = this.events.shift();
if (!event) {
this.report();
return;
}
this.emit('comment', {
text: this.commentator.comment(event),
gameInfo: event.gameInfo,
});
this.emit('event', event);
setTimeout(this.loop, this.gameSpeed);
};
Game.prototype.report = function () {
var reporter = new Reporter_1.default(this.engine.gameEvents);
report() {
const reporter = new Reporter(this.engine.gameEvents);
this.emit('report', reporter.getReport());
};
return Game;
}(events_1.EventEmitter));
exports.default = Game;
}
}

@@ -1,10 +0,4 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function getRandomElement(options) {
var weighted = options.map(function (_a) {
var action = _a[0], weight = _a[1];
return Array(weight).fill(action);
}).reduce(function (c, v) { return c.concat(v); }, []);
export default function getRandomElement(options) {
const weighted = options.map(([action, weight]) => Array(weight).fill(action)).reduce((c, v) => c.concat(v), []);
return weighted[Math.floor((Math.random() * weighted.length))];
}
exports.default = getRandomElement;
{
"name": "@bleckert/football-simulator",
"version": "0.0.5",
"version": "0.0.6",
"scripts": {

@@ -5,0 +5,0 @@ "start": "ts-node test/index.ts",

@@ -1,6 +0,8 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Position_1 = require("./enums/Position");
var Player = /** @class */ (function () {
function Player(info, biometrics, attributes, position) {
import { Position } from './enums/Position';
export default class Player {
info;
biometrics;
attributes;
position;
constructor(info, biometrics, attributes, position) {
this.info = info;

@@ -11,8 +13,8 @@ this.biometrics = biometrics;

}
Player.prototype.ratingAverage = function () {
var rating = this.rating();
return Object.values(rating).reduce(function (a, b) { return a + b; }) / Object.values(rating).length;
};
Player.prototype.rating = function () {
if (this.position === Position_1.Position.GK) {
ratingAverage() {
const rating = this.rating();
return Object.values(rating).reduce((a, b) => a + b) / Object.values(rating).length;
}
rating() {
if (this.position === Position.GK) {
return {

@@ -35,8 +37,8 @@ diving: this.attributesAverage(this.attributes.agility, this.attributes.balance, this.attributes.naturalFitness, this.attributes.strength),

};
};
Player.prototype.averageRating = function (ratings) {
return ratings.reduce(function (acc, curr) { return acc + curr; }) / ratings.length;
};
Player.prototype.defenceRating = function () {
var rating = this.rating();
}
averageRating(ratings) {
return ratings.reduce((acc, curr) => acc + curr) / ratings.length;
}
defenceRating() {
const rating = this.rating();
return this.averageRating([

@@ -47,5 +49,5 @@ rating.defending,

]);
};
Player.prototype.possessionRating = function () {
var rating = this.rating();
}
possessionRating() {
const rating = this.rating();
return this.averageRating([

@@ -56,5 +58,5 @@ rating.dribbling,

]);
};
Player.prototype.attackRating = function () {
var rating = this.rating();
}
attackRating() {
const rating = this.rating();
return this.averageRating([

@@ -67,12 +69,6 @@ rating.dribbling,

]);
};
Player.prototype.attributesAverage = function () {
var attributes = [];
for (var _i = 0; _i < arguments.length; _i++) {
attributes[_i] = arguments[_i];
}
return (attributes.reduce(function (a, b) { return a + b; }) / attributes.length) / 20 * 100;
};
return Player;
}());
exports.default = Player;
}
attributesAverage(...attributes) {
return (attributes.reduce((a, b) => a + b) / attributes.length) / 20 * 100;
}
}

@@ -1,63 +0,48 @@

"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
import { Event } from './enums/Event';
export default class Reporter {
gameEvents;
home = {
goals: 0,
possession: 0,
shots: 0,
shotsOnGoal: 0,
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var Event_1 = require("./enums/Event");
var Reporter = /** @class */ (function () {
function Reporter(gameEvents) {
var _this = this;
this.home = {
goals: 0,
possession: 0,
shots: 0,
shotsOnGoal: 0,
};
this.away = {
goals: 0,
possession: 0,
shots: 0,
shotsOnGoal: 0,
};
this.scoreSheet = [];
this.registerEvent = function (gameEvent) {
var side = (gameEvent.attackingTeam && gameEvent.attackingTeam.home) ? 'home' : 'away';
_this[side].possession += 1;
if ([Event_1.Event.Save, Event_1.Event.Goal, Event_1.Event.Block].includes(gameEvent.event)) {
_this[side].shots += 1;
}
if ([Event_1.Event.Save, Event_1.Event.Goal].includes(gameEvent.event)) {
_this[side].shotsOnGoal += 1;
}
if (gameEvent.event === Event_1.Event.Goal) {
_this[side].goals += 1;
_this.scoreSheet.push({
matchMinute: gameEvent.gameInfo.matchMinute,
goalScorer: gameEvent.attackingPrimaryPlayer,
assist: (gameEvent.assistType && gameEvent.attackingSecondaryPlayer) ? gameEvent.attackingSecondaryPlayer : false,
team: gameEvent.attackingTeam,
});
}
};
away = {
goals: 0,
possession: 0,
shots: 0,
shotsOnGoal: 0,
};
scoreSheet = [];
constructor(gameEvents) {
this.gameEvents = gameEvents;
}
Reporter.prototype.getReport = function () {
registerEvent = (gameEvent) => {
const side = (gameEvent.attackingTeam && gameEvent.attackingTeam.home) ? 'home' : 'away';
this[side].possession += 1;
if ([Event.Save, Event.Goal, Event.Block].includes(gameEvent.event)) {
this[side].shots += 1;
}
if ([Event.Save, Event.Goal].includes(gameEvent.event)) {
this[side].shotsOnGoal += 1;
}
if (gameEvent.event === Event.Goal) {
this[side].goals += 1;
this.scoreSheet.push({
matchMinute: gameEvent.gameInfo.matchMinute,
goalScorer: gameEvent.attackingPrimaryPlayer,
assist: (gameEvent.assistType && gameEvent.attackingSecondaryPlayer) ? gameEvent.attackingSecondaryPlayer : false,
team: gameEvent.attackingTeam,
});
}
};
getReport() {
this.gameEvents.forEach(this.registerEvent);
var totalPossession = this.home.possession + this.away.possession;
const totalPossession = this.home.possession + this.away.possession;
return {
home: __assign(__assign({}, this.home), { possession: this.home.possession / totalPossession }),
away: __assign(__assign({}, this.away), { possession: this.away.possession / totalPossession }),
home: { ...this.home, possession: this.home.possession / totalPossession },
away: { ...this.away, possession: this.away.possession / totalPossession },
scoreSheet: this.scoreSheet,
};
};
return Reporter;
}());
exports.default = Reporter;
}
}

@@ -1,12 +0,8 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Position_1 = require("./enums/Position");
var FieldArea_1 = require("./enums/FieldArea");
var Action_1 = require("./enums/Action");
var getRandomElement_1 = require("./lib/getRandomElement");
function createWeights(attacker) {
var _a;
if (attacker === void 0) { attacker = false; }
return _a = {},
_a[FieldArea_1.FieldArea.Defence] = {
import { defencePositions, midfieldPositions, Position } from './enums/Position';
import { FieldArea } from "./enums/FieldArea";
import { Action } from "./enums/Action";
import getRandomElement from "./lib/getRandomElement";
function createWeights(attacker = false) {
return {
[FieldArea.Defence]: {
defenders: (attacker) ? 0.6 : 0.1,

@@ -16,3 +12,3 @@ midfielders: 0.3,

},
_a[FieldArea_1.FieldArea.Midfield] = {
[FieldArea.Midfield]: {
defenders: 0.25,

@@ -22,11 +18,14 @@ midfielders: 0.5,

},
_a[FieldArea_1.FieldArea.Offense] = {
[FieldArea.Offense]: {
defenders: (attacker) ? 0.1 : 0.6,
midfielders: 0.3,
attackers: (attacker) ? 0.6 : 0.1,
},
_a;
}
};
}
var Team = /** @class */ (function () {
function Team(home, name, players) {
export default class Team {
players;
home;
name;
constructor(home, name, players) {
this.home = home;

@@ -36,3 +35,3 @@ this.name = name;

}
Team.prototype.rating = function () {
rating() {
return {

@@ -43,64 +42,57 @@ goalkeeping: this.goalkeeperRating(),

};
};
Team.prototype.getGoalkeepers = function () {
return this.players.filter(function (player) { return player.position === Position_1.Position.GK; });
};
Team.prototype.getFieldPlayers = function (exclude) {
if (exclude === void 0) { exclude = []; }
return this.players.filter(function (player) { return player.position !== Position_1.Position.GK; }).filter(function (player) { return !exclude.length || exclude.indexOf(player) < 0; });
};
Team.prototype.averageRating = function (map, players) {
if (players === void 0) { players = null; }
var playersList = (players) ? players : this.getFieldPlayers();
return playersList.map(map).reduce(function (a, b) { return a + b; }) / playersList.length;
};
Team.prototype.goalkeeperRating = function () {
return this.averageRating(function (player) { return player.ratingAverage(); }, this.getGoalkeepers());
};
Team.prototype.defenceRating = function () {
return this.averageRating(function (player) { return player.defenceRating(); });
};
Team.prototype.possessionRating = function () {
return this.averageRating(function (player) { return player.possessionRating(); });
};
Team.prototype.attackRating = function () {
return this.averageRating(function (player) { return player.attackRating(); });
};
Team.prototype.simulateMove = function (ballPosition, gameInfo) {
if (ballPosition === FieldArea_1.FieldArea.Offense) {
var options_1 = [[Action_1.Action.GoalAttempt, 50], [Action_1.Action.Stay, 35], [Action_1.Action.Retreat, 15]];
return getRandomElement_1.default(options_1);
}
getGoalkeepers() {
return this.players.filter(player => player.position === Position.GK);
}
getFieldPlayers(exclude = []) {
return this.players.filter(player => player.position !== Position.GK).filter(player => !exclude.length || exclude.indexOf(player) < 0);
}
averageRating(map, players = null) {
const playersList = (players) ? players : this.getFieldPlayers();
return playersList.map(map).reduce((a, b) => a + b) / playersList.length;
}
goalkeeperRating() {
return this.averageRating(player => player.ratingAverage(), this.getGoalkeepers());
}
defenceRating() {
return this.averageRating(player => player.defenceRating());
}
possessionRating() {
return this.averageRating(player => player.possessionRating());
}
attackRating() {
return this.averageRating(player => player.attackRating());
}
simulateMove(ballPosition, gameInfo) {
if (ballPosition === FieldArea.Offense) {
const options = [[Action.GoalAttempt, 50], [Action.Stay, 35], [Action.Retreat, 15]];
return getRandomElement(options);
}
var options = [[Action_1.Action.Advance, 50], [Action_1.Action.Stay, 35], [Action_1.Action.Retreat, 15]];
return getRandomElement_1.default(options);
};
Team.prototype.getProbablePlayer = function (fieldPosition, attacker, exclude) {
if (exclude === void 0) { exclude = []; }
var weights = createWeights(attacker);
var players = [];
this.getFieldPlayers(exclude).forEach(function (player) {
if (Position_1.defencePositions.indexOf(player.position) > -1) {
players.push({ player: player, weight: weights[fieldPosition].defenders });
const options = [[Action.Advance, 50], [Action.Stay, 35], [Action.Retreat, 15]];
return getRandomElement(options);
}
getProbablePlayer(fieldPosition, attacker, exclude = []) {
const weights = createWeights(attacker);
const players = [];
this.getFieldPlayers(exclude).forEach(player => {
if (defencePositions.indexOf(player.position) > -1) {
players.push({ player, weight: weights[fieldPosition].defenders });
}
else if (Position_1.midfieldPositions.indexOf(player.position) > -1) {
players.push({ player: player, weight: weights[fieldPosition].midfielders });
else if (midfieldPositions.indexOf(player.position) > -1) {
players.push({ player, weight: weights[fieldPosition].midfielders });
}
else {
players.push({ player: player, weight: weights[fieldPosition].attackers });
players.push({ player, weight: weights[fieldPosition].attackers });
}
});
var random = Math.min(Math.random(), 0.6);
var foundPlayers = players.filter(function (player) { return player.weight >= random; }).map(function (obj) { return obj.player; });
const random = Math.min(Math.random(), 0.6);
const foundPlayers = players.filter(player => player.weight >= random).map(obj => obj.player);
return foundPlayers[Math.floor(Math.random() * foundPlayers.length)];
};
Team.prototype.attacker = function (fieldPosition, exclude) {
if (exclude === void 0) { exclude = []; }
}
attacker(fieldPosition, exclude = []) {
return this.getProbablePlayer(fieldPosition, true, exclude);
};
Team.prototype.defender = function (fieldPosition, exclude) {
if (exclude === void 0) { exclude = []; }
}
defender(fieldPosition, exclude = []) {
return this.getProbablePlayer(fieldPosition, false, exclude);
};
return Team;
}());
exports.default = Team;
}
}

@@ -1,2 +0,1 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
export {};

@@ -1,2 +0,1 @@

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
export {};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc