volleyballsimtypes 0.0.510 → 0.0.511

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.
@@ -1,6 +1,7 @@
1
1
  export interface RallyMetricsEvent {
2
2
  readonly eventType: number;
3
3
  readonly failure?: number;
4
+ readonly type?: number;
4
5
  }
5
6
  export interface RallyMetricsRally {
6
7
  readonly servingTeamId: string;
@@ -14,7 +14,9 @@ function isServiceError(rally) {
14
14
  // engine scores a second spike as a transition). This counts first-ball kills and the block errors forced
15
15
  // on that first attack, and excludes service-error sideouts (no spike) and dig-and-transition rallies (2+).
16
16
  function spikeCount(rally) {
17
- return rally.events.reduce((n, e) => e.eventType === event_1.EventTypeEnum.SPIKE ? n + 1 : n, 0);
17
+ // An attack is a SPIKE, or a SET whose type is DUMP (the setter attacking on the second ball). Counting the
18
+ // dump matches the report builder's attack test, so a first-ball sideout won on a dump is not dropped.
19
+ return rally.events.reduce((n, e) => (e.eventType === event_1.EventTypeEnum.SPIKE || (e.eventType === event_1.EventTypeEnum.SET && e.type === event_1.SetTypeEnum.DUMP)) ? n + 1 : n, 0);
18
20
  }
19
21
  // The setter's zone after (rotationIndex - 1) rotations from their start zone, using the engine's own
20
22
  // rotatePosition (each rotation moves a player one zone: 2->1, 1->6, ...). null when no setter.
@@ -90,3 +90,25 @@ describe('computeRallyMetrics() first ball sideout', () => {
90
90
  expect(fm.total.home.modFbsoPct).toBe(0);
91
91
  });
92
92
  });
93
+ // The positional engine emits a setter DUMP as a SET event (type DUMP), not a SPIKE. A first-ball sideout won
94
+ // on a dump is still a first attack and must count as an FBSO. (Regression: spikeCount used to count only SPIKE.)
95
+ const dumpEv = () => ({ eventType: event_1.EventTypeEnum.SET, type: event_1.SetTypeEnum.DUMP, failure: 0 });
96
+ // serving H, A ; winners A, A (A 2 - H 0). A sides out on rally 0 via a single setter dump (no spike).
97
+ const dumpSet = {
98
+ homePoints: 0,
99
+ awayPoints: 2,
100
+ homeSetterStartZone: null,
101
+ awaySetterStartZone: null,
102
+ rallies: [
103
+ { servingTeamId: HOME, events: [serveEv(), dumpEv()] }, // A sideout on a dump -> A FBSO
104
+ { servingTeamId: AWAY, events: [serveEv()] } // A breakpoint (A serving) -> not a reception win
105
+ ]
106
+ };
107
+ const dm = (0, rally_metrics_1.computeRallyMetrics)([dumpSet], HOME, AWAY);
108
+ describe('computeRallyMetrics() first ball sideout - setter dump', () => {
109
+ it('counts a first-ball sideout won on a setter dump (SET type DUMP), not just a spike', () => {
110
+ expect(dm.total.away.receptions).toBe(1);
111
+ expect(dm.total.away.fbsoWins).toBe(1);
112
+ expect(dm.total.away.fbsoPct).toBeCloseTo(100, 5);
113
+ });
114
+ });
@@ -1,6 +1,7 @@
1
1
  export interface RallyMetricsEvent {
2
2
  readonly eventType: number;
3
3
  readonly failure?: number;
4
+ readonly type?: number;
4
5
  }
5
6
  export interface RallyMetricsRally {
6
7
  readonly servingTeamId: string;
@@ -1,4 +1,4 @@
1
- import { EventTypeEnum } from '../event';
1
+ import { EventTypeEnum, SetTypeEnum } from '../event';
2
2
  import { rotatePosition } from './court-position';
3
3
  function newAcc() {
4
4
  return { serves: 0, breakpointWins: 0, receptions: 0, sideoutWins: 0, serviceErrorsReceived: 0, fbsoWins: 0, rotations: new Map() };
@@ -11,7 +11,9 @@ function isServiceError(rally) {
11
11
  // engine scores a second spike as a transition). This counts first-ball kills and the block errors forced
12
12
  // on that first attack, and excludes service-error sideouts (no spike) and dig-and-transition rallies (2+).
13
13
  function spikeCount(rally) {
14
- return rally.events.reduce((n, e) => e.eventType === EventTypeEnum.SPIKE ? n + 1 : n, 0);
14
+ // An attack is a SPIKE, or a SET whose type is DUMP (the setter attacking on the second ball). Counting the
15
+ // dump matches the report builder's attack test, so a first-ball sideout won on a dump is not dropped.
16
+ return rally.events.reduce((n, e) => (e.eventType === EventTypeEnum.SPIKE || (e.eventType === EventTypeEnum.SET && e.type === SetTypeEnum.DUMP)) ? n + 1 : n, 0);
15
17
  }
16
18
  // The setter's zone after (rotationIndex - 1) rotations from their start zone, using the engine's own
17
19
  // rotatePosition (each rotation moves a player one zone: 2->1, 1->6, ...). null when no setter.
@@ -1,5 +1,5 @@
1
1
  import { computeRallyMetrics } from './rally-metrics';
2
- import { EventTypeEnum } from '../event';
2
+ import { EventTypeEnum, SetTypeEnum } from '../event';
3
3
  const serve = (failure = 0) => ({
4
4
  events: [{ eventType: EventTypeEnum.SERVE, failure }]
5
5
  });
@@ -88,3 +88,25 @@ describe('computeRallyMetrics() first ball sideout', () => {
88
88
  expect(fm.total.home.modFbsoPct).toBe(0);
89
89
  });
90
90
  });
91
+ // The positional engine emits a setter DUMP as a SET event (type DUMP), not a SPIKE. A first-ball sideout won
92
+ // on a dump is still a first attack and must count as an FBSO. (Regression: spikeCount used to count only SPIKE.)
93
+ const dumpEv = () => ({ eventType: EventTypeEnum.SET, type: SetTypeEnum.DUMP, failure: 0 });
94
+ // serving H, A ; winners A, A (A 2 - H 0). A sides out on rally 0 via a single setter dump (no spike).
95
+ const dumpSet = {
96
+ homePoints: 0,
97
+ awayPoints: 2,
98
+ homeSetterStartZone: null,
99
+ awaySetterStartZone: null,
100
+ rallies: [
101
+ { servingTeamId: HOME, events: [serveEv(), dumpEv()] }, // A sideout on a dump -> A FBSO
102
+ { servingTeamId: AWAY, events: [serveEv()] } // A breakpoint (A serving) -> not a reception win
103
+ ]
104
+ };
105
+ const dm = computeRallyMetrics([dumpSet], HOME, AWAY);
106
+ describe('computeRallyMetrics() first ball sideout - setter dump', () => {
107
+ it('counts a first-ball sideout won on a setter dump (SET type DUMP), not just a spike', () => {
108
+ expect(dm.total.away.receptions).toBe(1);
109
+ expect(dm.total.away.fbsoWins).toBe(1);
110
+ expect(dm.total.away.fbsoPct).toBeCloseTo(100, 5);
111
+ });
112
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volleyballsimtypes",
3
- "version": "0.0.510",
3
+ "version": "0.0.511",
4
4
  "description": "vbsim types",
5
5
  "main": "./dist/cjs/src/index.js",
6
6
  "module": "./dist/esm/src/index.js",