volleyballsimtypes 0.0.129 → 0.0.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,8 +9,8 @@ function transformToAttributes(team, rating) {
9
9
  return {
10
10
  match_id: rating.match.id,
11
11
  team_id: teamId,
12
- p: rating.getWinProbability(team),
13
- dR: rating.getRatingChange(team)
12
+ p: rating.getExpectedResult(),
13
+ dR: rating.getPoints(team)
14
14
  };
15
15
  }
16
16
  exports.transformFromMatchRating = transformToAttributes;
@@ -5,3 +5,7 @@ export * from './iteration';
5
5
  export * from './tournament';
6
6
  export * from './tournament-match';
7
7
  export * from './stage';
8
+ export declare enum _CompetitionType {
9
+ TOURNAMENT = "TOURNAMENT",
10
+ LEAGUE = "LEAGUE"
11
+ }
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports._CompetitionType = void 0;
17
18
  __exportStar(require("./standing"), exports);
18
19
  __exportStar(require("./season"), exports);
19
20
  __exportStar(require("./league"), exports);
@@ -21,3 +22,8 @@ __exportStar(require("./iteration"), exports);
21
22
  __exportStar(require("./tournament"), exports);
22
23
  __exportStar(require("./tournament-match"), exports);
23
24
  __exportStar(require("./stage"), exports);
25
+ var _CompetitionType;
26
+ (function (_CompetitionType) {
27
+ _CompetitionType["TOURNAMENT"] = "TOURNAMENT";
28
+ _CompetitionType["LEAGUE"] = "LEAGUE";
29
+ })(_CompetitionType = exports._CompetitionType || (exports._CompetitionType = {}));
@@ -1,12 +1,35 @@
1
1
  import { Match, MatchTeam } from '.';
2
+ import { CompetitionType } from '../../data';
2
3
  interface MatchRatingOpts {
3
4
  readonly match: Match;
5
+ readonly competitionType: CompetitionType;
6
+ }
7
+ interface SetScoreVariant {
8
+ '3-0': number;
9
+ '3-1': number;
10
+ '3-2': number;
11
+ '2-3': number;
12
+ '1-3': number;
13
+ '0-3': number;
14
+ }
15
+ interface MatchWeightFactor {
16
+ TOURNAMENT: number;
17
+ LEAGUE: number;
4
18
  }
5
19
  export declare class MatchRating {
6
20
  static K: number;
21
+ static SSV: SetScoreVariant;
22
+ static C1: number;
23
+ static C2: number;
24
+ static C3: number;
25
+ static C4: number;
26
+ static C5: number;
27
+ static MWF: MatchWeightFactor;
7
28
  readonly match: Match;
8
- constructor({ match }: MatchRatingOpts);
9
- getWinProbability(team: MatchTeam): number;
10
- getRatingChange(team: MatchTeam): number;
29
+ readonly weight: number;
30
+ constructor({ match, competitionType }: MatchRatingOpts);
31
+ getPoints(team: MatchTeam): number;
32
+ static calculateProbability(z: number): number;
33
+ getExpectedResult(): number;
11
34
  }
12
35
  export {};
@@ -3,27 +3,63 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MatchRating = void 0;
4
4
  const _1 = require(".");
5
5
  class MatchRating {
6
- constructor({ match }) {
6
+ constructor({ match, competitionType }) {
7
7
  this.match = match;
8
+ this.weight = MatchRating.MWF[competitionType];
8
9
  }
9
- getWinProbability(team) {
10
- let rA;
11
- let rB;
12
- if (team === _1.MatchTeam.HOME) {
13
- rA = this.match.homeTeam.rating;
14
- rB = this.match.awayTeam.rating;
15
- }
16
- else {
17
- rA = this.match.awayTeam.rating;
18
- rB = this.match.homeTeam.rating;
10
+ getPoints(team) {
11
+ const rankingValue = MatchRating.SSV[this.match.getScore()] - this.getExpectedResult();
12
+ const weighted = rankingValue * this.weight / MatchRating.K;
13
+ if (this.match.isWinner(team))
14
+ return weighted;
15
+ else
16
+ return weighted * -1;
17
+ }
18
+ static calculateProbability(z) {
19
+ let area = 0.0;
20
+ const rectangles = 100000;
21
+ const width = (z - (-10)) / rectangles;
22
+ for (let i = 0; i < rectangles; i++) {
23
+ area += width * Math.exp(-Math.pow((width * i + (-10)), 2) / 2) / Math.sqrt(2 * Math.PI);
19
24
  }
20
- return 1 / (1 + Math.pow(10, ((rB - rA) / 400)));
25
+ return area;
21
26
  }
22
- getRatingChange(team) {
23
- const t = this.match[team === _1.MatchTeam.HOME ? 'homeTeam' : 'awayTeam'];
24
- const score = this.match.getWinner().id === t.id ? 1 : 0;
25
- return MatchRating.K * (score - this.getWinProbability(team));
27
+ getExpectedResult() {
28
+ const D = MatchRating.K * (this.match.homeTeam.rating - this.match.awayTeam.rating) / 1000; // Strength difference between the teams
29
+ const P1 = MatchRating.calculateProbability(MatchRating.C1 + D); // 3-0
30
+ const P2 = MatchRating.calculateProbability(MatchRating.C2 + D) -
31
+ MatchRating.calculateProbability(MatchRating.C1 + D); // 3-1
32
+ const P3 = MatchRating.calculateProbability(MatchRating.C3 + D) -
33
+ MatchRating.calculateProbability(MatchRating.C2 + D); // 3-2
34
+ const P4 = MatchRating.calculateProbability(MatchRating.C4 + D) -
35
+ MatchRating.calculateProbability(MatchRating.C3 + D); // 2-3
36
+ const P5 = MatchRating.calculateProbability(MatchRating.C5 + D) -
37
+ MatchRating.calculateProbability(MatchRating.C4 + D); // 1-3
38
+ const P6 = 1 - MatchRating.calculateProbability(MatchRating.C5 + D); // 0-3
39
+ return P1 * MatchRating.SSV['3-0'] +
40
+ P2 * MatchRating.SSV['3-1'] +
41
+ P3 * MatchRating.SSV['3-2'] +
42
+ P4 * MatchRating.SSV['2-3'] +
43
+ P5 * MatchRating.SSV['1-3'] +
44
+ P6 * MatchRating.SSV['0-3']; // Expected Match Result EMR
26
45
  }
27
46
  }
28
47
  exports.MatchRating = MatchRating;
29
- MatchRating.K = 32; // I'll fix this here for medium variance
48
+ MatchRating.K = 8; // Standard scaling factor
49
+ MatchRating.SSV = {
50
+ [_1.MatchScore['3-0']]: 2,
51
+ [_1.MatchScore['3-1']]: 1.5,
52
+ [_1.MatchScore['3-2']]: 1,
53
+ [_1.MatchScore['2-3']]: -1,
54
+ [_1.MatchScore['1-3']]: -1.5,
55
+ [_1.MatchScore['0-3']]: -2
56
+ };
57
+ MatchRating.C1 = -1.060;
58
+ MatchRating.C2 = -0.394;
59
+ MatchRating.C3 = 0;
60
+ MatchRating.C4 = 0.394;
61
+ MatchRating.C5 = 1.060;
62
+ MatchRating.MWF = {
63
+ TOURNAMENT: 50,
64
+ LEAGUE: 35
65
+ };
@@ -9,6 +9,14 @@ interface MatchOpts {
9
9
  readonly sets: MatchSet[];
10
10
  readonly isSimulated: boolean;
11
11
  }
12
+ export declare enum MatchScore {
13
+ '3-0' = "3-0",
14
+ '3-1' = "3-1",
15
+ '3-2' = "3-2",
16
+ '2-3' = "2-3",
17
+ '1-3' = "1-3",
18
+ '0-3' = "0-3"
19
+ }
12
20
  export declare class Match {
13
21
  static readonly BEST_OF = 5;
14
22
  readonly id: string;
@@ -20,7 +28,9 @@ export declare class Match {
20
28
  constructor({ id, homeTeam, awayTeam, scheduledDate, sets, isSimulated }: MatchOpts);
21
29
  addSet(set: MatchSet): void;
22
30
  getTeamSets(team: MatchTeam): number;
31
+ getScore(): MatchScore;
23
32
  isOver(): boolean;
24
33
  getWinner(): Team;
34
+ isWinner(team: MatchTeam): boolean;
25
35
  }
26
36
  export {};
@@ -1,8 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Match = void 0;
3
+ exports.Match = exports.MatchScore = void 0;
4
4
  const utils_1 = require("../utils");
5
5
  const match_team_1 = require("./match-team");
6
+ var MatchScore;
7
+ (function (MatchScore) {
8
+ MatchScore["3-0"] = "3-0";
9
+ MatchScore["3-1"] = "3-1";
10
+ MatchScore["3-2"] = "3-2";
11
+ MatchScore["2-3"] = "2-3";
12
+ MatchScore["1-3"] = "1-3";
13
+ MatchScore["0-3"] = "0-3";
14
+ })(MatchScore = exports.MatchScore || (exports.MatchScore = {}));
6
15
  class Match {
7
16
  constructor({ id, homeTeam, awayTeam, scheduledDate, sets, isSimulated }) {
8
17
  (0, utils_1.validateUUID)(id);
@@ -21,6 +30,9 @@ class Match {
21
30
  getTeamSets(team) {
22
31
  return this.sets.reduce((sets, set) => sets + (!set.isOver() ? 0 : set.getWinner() === team ? 1 : 0), 0);
23
32
  }
33
+ getScore() {
34
+ return `${this.getTeamSets(match_team_1.MatchTeam.HOME)}-${this.getTeamSets(match_team_1.MatchTeam.AWAY)}`;
35
+ }
24
36
  isOver() {
25
37
  const gamesRequired = Math.ceil(Match.BEST_OF / 2);
26
38
  const lastSet = this.sets.at(-1);
@@ -38,6 +50,12 @@ class Match {
38
50
  const awaySets = this.getTeamSets(match_team_1.MatchTeam.AWAY);
39
51
  return homeSets > awaySets ? this.homeTeam : this.awayTeam;
40
52
  }
53
+ isWinner(team) {
54
+ if (team === match_team_1.MatchTeam.HOME && this.getWinner() === this.homeTeam)
55
+ return true;
56
+ else
57
+ return team === match_team_1.MatchTeam.AWAY && this.getWinner() === this.awayTeam;
58
+ }
41
59
  }
42
60
  exports.Match = Match;
43
61
  Match.BEST_OF = 5;
@@ -26,6 +26,6 @@ export declare class Team {
26
26
  set rating(value: number);
27
27
  isPlayerInRoster(player: Player): boolean;
28
28
  toString(): string;
29
- updateRating(ratingChange: number): void;
29
+ updateRating(rankingPoints: number): void;
30
30
  }
31
31
  export {};
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Team = void 0;
4
4
  const utils_1 = require("../utils");
5
- const match_1 = require("../match");
6
5
  class Team {
7
6
  constructor({ id, rating, name, shortName, country, roster, coach, league }) {
8
7
  (0, utils_1.validateUUID)(id);
@@ -30,10 +29,8 @@ class Team {
30
29
  }
31
30
  return `${this.name} [${this.shortName}] (${this.country?.name}) ELO=${this._rating}`;
32
31
  }
33
- updateRating(ratingChange) {
34
- if (Math.abs(ratingChange) > match_1.MatchRating.K)
35
- throw new Error(`INVALID RATING CHANGE: ${ratingChange}`);
36
- this._rating += ratingChange;
32
+ updateRating(rankingPoints) {
33
+ this._rating += rankingPoints;
37
34
  }
38
35
  }
39
36
  exports.Team = Team;
@@ -6,8 +6,8 @@ function transformToAttributes(team, rating) {
6
6
  return {
7
7
  match_id: rating.match.id,
8
8
  team_id: teamId,
9
- p: rating.getWinProbability(team),
10
- dR: rating.getRatingChange(team)
9
+ p: rating.getExpectedResult(),
10
+ dR: rating.getPoints(team)
11
11
  };
12
12
  }
13
13
  export { transformToAttributes as transformFromMatchRating };
@@ -5,3 +5,7 @@ export * from './iteration';
5
5
  export * from './tournament';
6
6
  export * from './tournament-match';
7
7
  export * from './stage';
8
+ export declare enum _CompetitionType {
9
+ TOURNAMENT = "TOURNAMENT",
10
+ LEAGUE = "LEAGUE"
11
+ }
@@ -5,3 +5,8 @@ export * from './iteration';
5
5
  export * from './tournament';
6
6
  export * from './tournament-match';
7
7
  export * from './stage';
8
+ export var _CompetitionType;
9
+ (function (_CompetitionType) {
10
+ _CompetitionType["TOURNAMENT"] = "TOURNAMENT";
11
+ _CompetitionType["LEAGUE"] = "LEAGUE";
12
+ })(_CompetitionType || (_CompetitionType = {}));
@@ -1,12 +1,35 @@
1
1
  import { Match, MatchTeam } from '.';
2
+ import { CompetitionType } from '../../data';
2
3
  interface MatchRatingOpts {
3
4
  readonly match: Match;
5
+ readonly competitionType: CompetitionType;
6
+ }
7
+ interface SetScoreVariant {
8
+ '3-0': number;
9
+ '3-1': number;
10
+ '3-2': number;
11
+ '2-3': number;
12
+ '1-3': number;
13
+ '0-3': number;
14
+ }
15
+ interface MatchWeightFactor {
16
+ TOURNAMENT: number;
17
+ LEAGUE: number;
4
18
  }
5
19
  export declare class MatchRating {
6
20
  static K: number;
21
+ static SSV: SetScoreVariant;
22
+ static C1: number;
23
+ static C2: number;
24
+ static C3: number;
25
+ static C4: number;
26
+ static C5: number;
27
+ static MWF: MatchWeightFactor;
7
28
  readonly match: Match;
8
- constructor({ match }: MatchRatingOpts);
9
- getWinProbability(team: MatchTeam): number;
10
- getRatingChange(team: MatchTeam): number;
29
+ readonly weight: number;
30
+ constructor({ match, competitionType }: MatchRatingOpts);
31
+ getPoints(team: MatchTeam): number;
32
+ static calculateProbability(z: number): number;
33
+ getExpectedResult(): number;
11
34
  }
12
35
  export {};
@@ -1,25 +1,61 @@
1
- import { MatchTeam } from '.';
1
+ import { MatchScore } from '.';
2
2
  export class MatchRating {
3
- constructor({ match }) {
3
+ constructor({ match, competitionType }) {
4
4
  this.match = match;
5
+ this.weight = MatchRating.MWF[competitionType];
5
6
  }
6
- getWinProbability(team) {
7
- let rA;
8
- let rB;
9
- if (team === MatchTeam.HOME) {
10
- rA = this.match.homeTeam.rating;
11
- rB = this.match.awayTeam.rating;
12
- }
13
- else {
14
- rA = this.match.awayTeam.rating;
15
- rB = this.match.homeTeam.rating;
7
+ getPoints(team) {
8
+ const rankingValue = MatchRating.SSV[this.match.getScore()] - this.getExpectedResult();
9
+ const weighted = rankingValue * this.weight / MatchRating.K;
10
+ if (this.match.isWinner(team))
11
+ return weighted;
12
+ else
13
+ return weighted * -1;
14
+ }
15
+ static calculateProbability(z) {
16
+ let area = 0.0;
17
+ const rectangles = 100000;
18
+ const width = (z - (-10)) / rectangles;
19
+ for (let i = 0; i < rectangles; i++) {
20
+ area += width * Math.exp(-Math.pow((width * i + (-10)), 2) / 2) / Math.sqrt(2 * Math.PI);
16
21
  }
17
- return 1 / (1 + Math.pow(10, ((rB - rA) / 400)));
22
+ return area;
18
23
  }
19
- getRatingChange(team) {
20
- const t = this.match[team === MatchTeam.HOME ? 'homeTeam' : 'awayTeam'];
21
- const score = this.match.getWinner().id === t.id ? 1 : 0;
22
- return MatchRating.K * (score - this.getWinProbability(team));
24
+ getExpectedResult() {
25
+ const D = MatchRating.K * (this.match.homeTeam.rating - this.match.awayTeam.rating) / 1000; // Strength difference between the teams
26
+ const P1 = MatchRating.calculateProbability(MatchRating.C1 + D); // 3-0
27
+ const P2 = MatchRating.calculateProbability(MatchRating.C2 + D) -
28
+ MatchRating.calculateProbability(MatchRating.C1 + D); // 3-1
29
+ const P3 = MatchRating.calculateProbability(MatchRating.C3 + D) -
30
+ MatchRating.calculateProbability(MatchRating.C2 + D); // 3-2
31
+ const P4 = MatchRating.calculateProbability(MatchRating.C4 + D) -
32
+ MatchRating.calculateProbability(MatchRating.C3 + D); // 2-3
33
+ const P5 = MatchRating.calculateProbability(MatchRating.C5 + D) -
34
+ MatchRating.calculateProbability(MatchRating.C4 + D); // 1-3
35
+ const P6 = 1 - MatchRating.calculateProbability(MatchRating.C5 + D); // 0-3
36
+ return P1 * MatchRating.SSV['3-0'] +
37
+ P2 * MatchRating.SSV['3-1'] +
38
+ P3 * MatchRating.SSV['3-2'] +
39
+ P4 * MatchRating.SSV['2-3'] +
40
+ P5 * MatchRating.SSV['1-3'] +
41
+ P6 * MatchRating.SSV['0-3']; // Expected Match Result EMR
23
42
  }
24
43
  }
25
- MatchRating.K = 32; // I'll fix this here for medium variance
44
+ MatchRating.K = 8; // Standard scaling factor
45
+ MatchRating.SSV = {
46
+ [MatchScore['3-0']]: 2,
47
+ [MatchScore['3-1']]: 1.5,
48
+ [MatchScore['3-2']]: 1,
49
+ [MatchScore['2-3']]: -1,
50
+ [MatchScore['1-3']]: -1.5,
51
+ [MatchScore['0-3']]: -2
52
+ };
53
+ MatchRating.C1 = -1.060;
54
+ MatchRating.C2 = -0.394;
55
+ MatchRating.C3 = 0;
56
+ MatchRating.C4 = 0.394;
57
+ MatchRating.C5 = 1.060;
58
+ MatchRating.MWF = {
59
+ TOURNAMENT: 50,
60
+ LEAGUE: 35
61
+ };
@@ -9,6 +9,14 @@ interface MatchOpts {
9
9
  readonly sets: MatchSet[];
10
10
  readonly isSimulated: boolean;
11
11
  }
12
+ export declare enum MatchScore {
13
+ '3-0' = "3-0",
14
+ '3-1' = "3-1",
15
+ '3-2' = "3-2",
16
+ '2-3' = "2-3",
17
+ '1-3' = "1-3",
18
+ '0-3' = "0-3"
19
+ }
12
20
  export declare class Match {
13
21
  static readonly BEST_OF = 5;
14
22
  readonly id: string;
@@ -20,7 +28,9 @@ export declare class Match {
20
28
  constructor({ id, homeTeam, awayTeam, scheduledDate, sets, isSimulated }: MatchOpts);
21
29
  addSet(set: MatchSet): void;
22
30
  getTeamSets(team: MatchTeam): number;
31
+ getScore(): MatchScore;
23
32
  isOver(): boolean;
24
33
  getWinner(): Team;
34
+ isWinner(team: MatchTeam): boolean;
25
35
  }
26
36
  export {};
@@ -1,5 +1,14 @@
1
1
  import { validateUUID } from '../utils';
2
2
  import { MatchTeam } from './match-team';
3
+ export var MatchScore;
4
+ (function (MatchScore) {
5
+ MatchScore["3-0"] = "3-0";
6
+ MatchScore["3-1"] = "3-1";
7
+ MatchScore["3-2"] = "3-2";
8
+ MatchScore["2-3"] = "2-3";
9
+ MatchScore["1-3"] = "1-3";
10
+ MatchScore["0-3"] = "0-3";
11
+ })(MatchScore || (MatchScore = {}));
3
12
  export class Match {
4
13
  constructor({ id, homeTeam, awayTeam, scheduledDate, sets, isSimulated }) {
5
14
  validateUUID(id);
@@ -18,6 +27,9 @@ export class Match {
18
27
  getTeamSets(team) {
19
28
  return this.sets.reduce((sets, set) => sets + (!set.isOver() ? 0 : set.getWinner() === team ? 1 : 0), 0);
20
29
  }
30
+ getScore() {
31
+ return `${this.getTeamSets(MatchTeam.HOME)}-${this.getTeamSets(MatchTeam.AWAY)}`;
32
+ }
21
33
  isOver() {
22
34
  const gamesRequired = Math.ceil(Match.BEST_OF / 2);
23
35
  const lastSet = this.sets.at(-1);
@@ -35,5 +47,11 @@ export class Match {
35
47
  const awaySets = this.getTeamSets(MatchTeam.AWAY);
36
48
  return homeSets > awaySets ? this.homeTeam : this.awayTeam;
37
49
  }
50
+ isWinner(team) {
51
+ if (team === MatchTeam.HOME && this.getWinner() === this.homeTeam)
52
+ return true;
53
+ else
54
+ return team === MatchTeam.AWAY && this.getWinner() === this.awayTeam;
55
+ }
38
56
  }
39
57
  Match.BEST_OF = 5;
@@ -26,6 +26,6 @@ export declare class Team {
26
26
  set rating(value: number);
27
27
  isPlayerInRoster(player: Player): boolean;
28
28
  toString(): string;
29
- updateRating(ratingChange: number): void;
29
+ updateRating(rankingPoints: number): void;
30
30
  }
31
31
  export {};
@@ -1,5 +1,4 @@
1
1
  import { validateUUID } from '../utils';
2
- import { MatchRating } from '../match';
3
2
  export class Team {
4
3
  constructor({ id, rating, name, shortName, country, roster, coach, league }) {
5
4
  validateUUID(id);
@@ -27,9 +26,7 @@ export class Team {
27
26
  }
28
27
  return `${this.name} [${this.shortName}] (${this.country?.name}) ELO=${this._rating}`;
29
28
  }
30
- updateRating(ratingChange) {
31
- if (Math.abs(ratingChange) > MatchRating.K)
32
- throw new Error(`INVALID RATING CHANGE: ${ratingChange}`);
33
- this._rating += ratingChange;
29
+ updateRating(rankingPoints) {
30
+ this._rating += rankingPoints;
34
31
  }
35
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volleyballsimtypes",
3
- "version": "0.0.129",
3
+ "version": "0.0.131",
4
4
  "description": "vbsim types",
5
5
  "main": "./dist/cjs/src/index.js",
6
6
  "module": "./dist/esm/src/index.js",