volleyballsimtypes 0.0.429 → 0.0.430

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.
@@ -17,16 +17,14 @@ export declare class MatchRating {
17
17
  static readonly C4: number;
18
18
  static readonly C5: number;
19
19
  static readonly SSV: SetScoreVariant;
20
- static readonly LEAGUE_BASE: number;
21
- static readonly TIER_PENALTY: number;
20
+ static readonly LEAGUE_WEIGHT: number;
21
+ static readonly NATIONAL_WEIGHT: number;
22
22
  static readonly QUALIFIER_WEIGHT: number;
23
23
  static readonly TOURNAMENT_WEIGHT: number;
24
- static readonly NATIONAL_WEIGHT: number;
25
24
  readonly match: Match;
26
25
  readonly weight: number;
27
26
  static create(input: unknown): MatchRating;
28
27
  private constructor();
29
- private static leagueWeight;
30
28
  private static applyBotPenalty;
31
29
  private static computeWeight;
32
30
  static calculateProbability(z: number): number;
@@ -21,23 +21,16 @@ class MatchRating {
21
21
  this.match = match;
22
22
  this.weight = MatchRating.computeWeight(context);
23
23
  }
24
- static leagueWeight(tier) {
25
- return Math.max(MatchRating.TIER_PENALTY, MatchRating.LEAGUE_BASE - MatchRating.TIER_PENALTY * tier);
26
- }
27
24
  static applyBotPenalty(weight, homeIsBot, awayIsBot) {
28
25
  const bots = (homeIsBot ? 1 : 0) + (awayIsBot ? 1 : 0);
29
26
  return weight * Math.pow(0.5, bots);
30
27
  }
31
28
  static computeWeight(context) {
32
29
  switch (context.kind) {
33
- case 'LEAGUE': {
34
- const base = MatchRating.leagueWeight(context.tier);
35
- return MatchRating.applyBotPenalty(base, context.homeIsBot, context.awayIsBot);
36
- }
37
- case 'PROMOTION': {
38
- const base = (MatchRating.leagueWeight(context.upperTier) + MatchRating.leagueWeight(context.lowerTier)) / 2;
39
- return MatchRating.applyBotPenalty(base, context.homeIsBot, context.awayIsBot);
40
- }
30
+ // Promotion plays at the league weight (it is a league-tier playoff).
31
+ case 'LEAGUE':
32
+ case 'PROMOTION':
33
+ return MatchRating.applyBotPenalty(MatchRating.LEAGUE_WEIGHT, context.homeIsBot, context.awayIsBot);
41
34
  case 'QUALIFIER':
42
35
  return MatchRating.applyBotPenalty(MatchRating.QUALIFIER_WEIGHT, context.homeIsBot, context.awayIsBot);
43
36
  case 'TOURNAMENT':
@@ -89,13 +82,10 @@ MatchRating.SSV = {
89
82
  '1-3': -1.5,
90
83
  '0-3': -2
91
84
  };
92
- // League weight = LEAGUE_BASE - TIER_PENALTY * tier
93
- // Tier 1 35, Tier 2 30, Tier 3 → 25, Tier 4 20, ...
94
- MatchRating.LEAGUE_BASE = 40;
95
- MatchRating.TIER_PENALTY = 5;
96
- // Regional qualifier — higher prestige than any league tier
97
- MatchRating.QUALIFIER_WEIGHT = 45;
98
- // WCC tournament — top of the hierarchy
99
- MatchRating.TOURNAMENT_WEIGHT = 55;
100
- // National cup, between qualifier and tournament prestige
101
- MatchRating.NATIONAL_WEIGHT = 50;
85
+ // FIVB tournament-importance weight: FIVB's "K" in S_after = S_before + K*(R-E)/8 (note the static `K`
86
+ // below is the formula's /8 divisor, NOT this). One flat value per competition, FIVB-style no per-tier
87
+ // or per-stage scaling, since the rating-gap expected result already rewards beating stronger teams.
88
+ MatchRating.LEAGUE_WEIGHT = 20;
89
+ MatchRating.NATIONAL_WEIGHT = 30;
90
+ MatchRating.QUALIFIER_WEIGHT = 40;
91
+ MatchRating.TOURNAMENT_WEIGHT = 50; // WCC, top of the hierarchy
@@ -37,22 +37,21 @@ const number_utils_1 = require("../utils/number-utils");
37
37
  const match = (0, test_helpers_1.makeMatch30)(home, away);
38
38
  return match_rating_1.MatchRating.create({ match, context });
39
39
  }
40
- (0, globals_1.it)('LEAGUE tier 1 weight = LEAGUE_BASE - TIER_PENALTY * 1 = 35', () => {
41
- const mr = makeRating({ kind: 'LEAGUE', tier: 1, homeIsBot: false, awayIsBot: false });
42
- (0, globals_1.expect)(mr.weight).toBe(35);
40
+ (0, globals_1.it)('LEAGUE → flat LEAGUE_WEIGHT (20), independent of tier', () => {
41
+ (0, globals_1.expect)(makeRating({ kind: 'LEAGUE', tier: 1, homeIsBot: false, awayIsBot: false }).weight).toBe(20);
42
+ (0, globals_1.expect)(makeRating({ kind: 'LEAGUE', tier: 7, homeIsBot: false, awayIsBot: false }).weight).toBe(20);
43
43
  });
44
- (0, globals_1.it)('LEAGUE tier 7 → weight is floored at TIER_PENALTY (5)', () => {
45
- // 40 - 5*7 = 5 (minimum is TIER_PENALTY itself)
46
- const mr = makeRating({ kind: 'LEAGUE', tier: 7, homeIsBot: false, awayIsBot: false });
47
- (0, globals_1.expect)(mr.weight).toBe(5);
44
+ (0, globals_1.it)('NATIONAL → weight = NATIONAL_WEIGHT (30)', () => {
45
+ const mr = makeRating({ kind: 'NATIONAL', homeIsBot: false, awayIsBot: false });
46
+ (0, globals_1.expect)(mr.weight).toBe(30);
48
47
  });
49
- (0, globals_1.it)('QUALIFIER → weight = QUALIFIER_WEIGHT (45)', () => {
48
+ (0, globals_1.it)('QUALIFIER → weight = QUALIFIER_WEIGHT (40)', () => {
50
49
  const mr = makeRating({ kind: 'QUALIFIER', homeIsBot: false, awayIsBot: false });
51
- (0, globals_1.expect)(mr.weight).toBe(45);
50
+ (0, globals_1.expect)(mr.weight).toBe(40);
52
51
  });
53
- (0, globals_1.it)('TOURNAMENT → weight = TOURNAMENT_WEIGHT (55)', () => {
52
+ (0, globals_1.it)('TOURNAMENT → weight = TOURNAMENT_WEIGHT (50)', () => {
54
53
  const mr = makeRating({ kind: 'TOURNAMENT', homeIsBot: false, awayIsBot: false });
55
- (0, globals_1.expect)(mr.weight).toBe(55);
54
+ (0, globals_1.expect)(mr.weight).toBe(50);
56
55
  });
57
56
  (0, globals_1.it)('each bot halves the weight', () => {
58
57
  const noBots = makeRating({ kind: 'QUALIFIER', homeIsBot: false, awayIsBot: false });
@@ -61,10 +60,9 @@ const number_utils_1 = require("../utils/number-utils");
61
60
  (0, globals_1.expect)(oneBot.weight).toBeCloseTo(noBots.weight * 0.5, 10);
62
61
  (0, globals_1.expect)(twoBots.weight).toBeCloseTo(noBots.weight * 0.25, 10);
63
62
  });
64
- (0, globals_1.it)('PROMOTION weight is the average of the two league tier weights', () => {
65
- // upperTier=1 (35), lowerTier=2 (30) → avg = 32.5
63
+ (0, globals_1.it)('PROMOTION league weight (20)', () => {
66
64
  const mr = makeRating({ kind: 'PROMOTION', upperTier: 1, lowerTier: 2, homeIsBot: false, awayIsBot: false });
67
- (0, globals_1.expect)(mr.weight).toBeCloseTo(32.5, 5);
65
+ (0, globals_1.expect)(mr.weight).toBe(20);
68
66
  });
69
67
  });
70
68
  // ─── getExpectedResult ────────────────────────────────────────────────────────
@@ -17,16 +17,14 @@ export declare class MatchRating {
17
17
  static readonly C4: number;
18
18
  static readonly C5: number;
19
19
  static readonly SSV: SetScoreVariant;
20
- static readonly LEAGUE_BASE: number;
21
- static readonly TIER_PENALTY: number;
20
+ static readonly LEAGUE_WEIGHT: number;
21
+ static readonly NATIONAL_WEIGHT: number;
22
22
  static readonly QUALIFIER_WEIGHT: number;
23
23
  static readonly TOURNAMENT_WEIGHT: number;
24
- static readonly NATIONAL_WEIGHT: number;
25
24
  readonly match: Match;
26
25
  readonly weight: number;
27
26
  static create(input: unknown): MatchRating;
28
27
  private constructor();
29
- private static leagueWeight;
30
28
  private static applyBotPenalty;
31
29
  private static computeWeight;
32
30
  static calculateProbability(z: number): number;
@@ -18,23 +18,16 @@ export class MatchRating {
18
18
  this.match = match;
19
19
  this.weight = MatchRating.computeWeight(context);
20
20
  }
21
- static leagueWeight(tier) {
22
- return Math.max(MatchRating.TIER_PENALTY, MatchRating.LEAGUE_BASE - MatchRating.TIER_PENALTY * tier);
23
- }
24
21
  static applyBotPenalty(weight, homeIsBot, awayIsBot) {
25
22
  const bots = (homeIsBot ? 1 : 0) + (awayIsBot ? 1 : 0);
26
23
  return weight * Math.pow(0.5, bots);
27
24
  }
28
25
  static computeWeight(context) {
29
26
  switch (context.kind) {
30
- case 'LEAGUE': {
31
- const base = MatchRating.leagueWeight(context.tier);
32
- return MatchRating.applyBotPenalty(base, context.homeIsBot, context.awayIsBot);
33
- }
34
- case 'PROMOTION': {
35
- const base = (MatchRating.leagueWeight(context.upperTier) + MatchRating.leagueWeight(context.lowerTier)) / 2;
36
- return MatchRating.applyBotPenalty(base, context.homeIsBot, context.awayIsBot);
37
- }
27
+ // Promotion plays at the league weight (it is a league-tier playoff).
28
+ case 'LEAGUE':
29
+ case 'PROMOTION':
30
+ return MatchRating.applyBotPenalty(MatchRating.LEAGUE_WEIGHT, context.homeIsBot, context.awayIsBot);
38
31
  case 'QUALIFIER':
39
32
  return MatchRating.applyBotPenalty(MatchRating.QUALIFIER_WEIGHT, context.homeIsBot, context.awayIsBot);
40
33
  case 'TOURNAMENT':
@@ -85,13 +78,10 @@ MatchRating.SSV = {
85
78
  '1-3': -1.5,
86
79
  '0-3': -2
87
80
  };
88
- // League weight = LEAGUE_BASE - TIER_PENALTY * tier
89
- // Tier 1 35, Tier 2 30, Tier 3 → 25, Tier 4 20, ...
90
- MatchRating.LEAGUE_BASE = 40;
91
- MatchRating.TIER_PENALTY = 5;
92
- // Regional qualifier — higher prestige than any league tier
93
- MatchRating.QUALIFIER_WEIGHT = 45;
94
- // WCC tournament — top of the hierarchy
95
- MatchRating.TOURNAMENT_WEIGHT = 55;
96
- // National cup, between qualifier and tournament prestige
97
- MatchRating.NATIONAL_WEIGHT = 50;
81
+ // FIVB tournament-importance weight: FIVB's "K" in S_after = S_before + K*(R-E)/8 (note the static `K`
82
+ // below is the formula's /8 divisor, NOT this). One flat value per competition, FIVB-style no per-tier
83
+ // or per-stage scaling, since the rating-gap expected result already rewards beating stronger teams.
84
+ MatchRating.LEAGUE_WEIGHT = 20;
85
+ MatchRating.NATIONAL_WEIGHT = 30;
86
+ MatchRating.QUALIFIER_WEIGHT = 40;
87
+ MatchRating.TOURNAMENT_WEIGHT = 50; // WCC, top of the hierarchy
@@ -35,22 +35,21 @@ describe('MatchRating weight computation', () => {
35
35
  const match = makeMatch30(home, away);
36
36
  return MatchRating.create({ match, context });
37
37
  }
38
- it('LEAGUE tier 1 weight = LEAGUE_BASE - TIER_PENALTY * 1 = 35', () => {
39
- const mr = makeRating({ kind: 'LEAGUE', tier: 1, homeIsBot: false, awayIsBot: false });
40
- expect(mr.weight).toBe(35);
38
+ it('LEAGUE → flat LEAGUE_WEIGHT (20), independent of tier', () => {
39
+ expect(makeRating({ kind: 'LEAGUE', tier: 1, homeIsBot: false, awayIsBot: false }).weight).toBe(20);
40
+ expect(makeRating({ kind: 'LEAGUE', tier: 7, homeIsBot: false, awayIsBot: false }).weight).toBe(20);
41
41
  });
42
- it('LEAGUE tier 7 → weight is floored at TIER_PENALTY (5)', () => {
43
- // 40 - 5*7 = 5 (minimum is TIER_PENALTY itself)
44
- const mr = makeRating({ kind: 'LEAGUE', tier: 7, homeIsBot: false, awayIsBot: false });
45
- expect(mr.weight).toBe(5);
42
+ it('NATIONAL → weight = NATIONAL_WEIGHT (30)', () => {
43
+ const mr = makeRating({ kind: 'NATIONAL', homeIsBot: false, awayIsBot: false });
44
+ expect(mr.weight).toBe(30);
46
45
  });
47
- it('QUALIFIER → weight = QUALIFIER_WEIGHT (45)', () => {
46
+ it('QUALIFIER → weight = QUALIFIER_WEIGHT (40)', () => {
48
47
  const mr = makeRating({ kind: 'QUALIFIER', homeIsBot: false, awayIsBot: false });
49
- expect(mr.weight).toBe(45);
48
+ expect(mr.weight).toBe(40);
50
49
  });
51
- it('TOURNAMENT → weight = TOURNAMENT_WEIGHT (55)', () => {
50
+ it('TOURNAMENT → weight = TOURNAMENT_WEIGHT (50)', () => {
52
51
  const mr = makeRating({ kind: 'TOURNAMENT', homeIsBot: false, awayIsBot: false });
53
- expect(mr.weight).toBe(55);
52
+ expect(mr.weight).toBe(50);
54
53
  });
55
54
  it('each bot halves the weight', () => {
56
55
  const noBots = makeRating({ kind: 'QUALIFIER', homeIsBot: false, awayIsBot: false });
@@ -59,10 +58,9 @@ describe('MatchRating weight computation', () => {
59
58
  expect(oneBot.weight).toBeCloseTo(noBots.weight * 0.5, 10);
60
59
  expect(twoBots.weight).toBeCloseTo(noBots.weight * 0.25, 10);
61
60
  });
62
- it('PROMOTION weight is the average of the two league tier weights', () => {
63
- // upperTier=1 (35), lowerTier=2 (30) → avg = 32.5
61
+ it('PROMOTION league weight (20)', () => {
64
62
  const mr = makeRating({ kind: 'PROMOTION', upperTier: 1, lowerTier: 2, homeIsBot: false, awayIsBot: false });
65
- expect(mr.weight).toBeCloseTo(32.5, 5);
63
+ expect(mr.weight).toBe(20);
66
64
  });
67
65
  });
68
66
  // ─── getExpectedResult ────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volleyballsimtypes",
3
- "version": "0.0.429",
3
+ "version": "0.0.430",
4
4
  "description": "vbsim types",
5
5
  "main": "./dist/cjs/src/index.js",
6
6
  "module": "./dist/esm/src/index.js",