• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

project-slippi / slippi-js / 21323792116

25 Jan 2026 12:06AM UTC coverage: 80.939% (-0.03%) from 80.966%
21323792116

Pull #165

github

web-flow
Merge af1fccff9 into 5cc4df949
Pull Request #165: checks if both players have 0 stocks in the last frame, return []

700 of 933 branches covered (75.03%)

Branch coverage included in aggregate %.

4 of 5 new or added lines in 1 file covered. (80.0%)

1 existing line in 1 file now uncovered.

1869 of 2241 relevant lines covered (83.4%)

126488.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/src/common/utils/getWinners.ts
1
import type { GameEndType, GameStartType, PlacementType, PostFrameUpdateType } from "../types";
2
import { GameEndMethod } from "../types";
12✔
3
import { exists } from "./exists";
12✔
4

5
export function getWinners(
12✔
6
  gameEnd: GameEndType,
7
  settings: Pick<GameStartType, "players" | "isTeams">,
8
  finalPostFrameUpdates: PostFrameUpdateType[],
9
): PlacementType[] {
10
  const { placements, gameEndMethod, lrasInitiatorIndex } = gameEnd;
4✔
11
  const { players, isTeams } = settings;
4✔
12

13
  if (gameEndMethod === GameEndMethod.NO_CONTEST || gameEndMethod === GameEndMethod.UNRESOLVED) {
4✔
14
    // The winner is the person who didn't LRAS
15
    if (exists(lrasInitiatorIndex) && players.length === 2) {
1✔
16
      const winnerIndex = players.find(({ playerIndex }) => playerIndex !== lrasInitiatorIndex)?.playerIndex;
2!
17
      if (exists(winnerIndex)) {
1✔
18
        return [
1✔
19
          {
20
            playerIndex: winnerIndex,
21
            position: 0,
22
          },
23
        ];
24
      }
25
    }
26

27
    return [];
×
28
  }
29

30
  const nonFollowerUpdates = finalPostFrameUpdates.filter((pfu) => !pfu.isFollower);
5✔
31

32
  // If everyone has no stocks at the last frame, then we handle it by returning []
33
  if (nonFollowerUpdates.length === players.length) {
3✔
34
    const everyoneDead = nonFollowerUpdates.every((pfu) => pfu.stocksRemaining === 0);
1✔
35
    if (everyoneDead) {
1!
NEW
36
      return [];
×
37
    }
38
  }
39

40
  if (gameEndMethod === GameEndMethod.TIME && players.length === 2) {
3✔
41
    if (nonFollowerUpdates.length !== players.length) {
1!
UNCOV
42
      return [];
×
43
    }
44

45
    const p1 = nonFollowerUpdates[0]!;
1✔
46
    const p2 = nonFollowerUpdates[1]!;
1✔
47
    if (p1.stocksRemaining! > p2.stocksRemaining!) {
1!
48
      return [{ playerIndex: p1.playerIndex!, position: 0 }];
×
49
    } else if (p2.stocksRemaining! > p1.stocksRemaining!) {
1!
50
      return [{ playerIndex: p2.playerIndex!, position: 0 }];
×
51
    }
52

53
    const p1Health = Math.trunc(p1.percent!);
1✔
54
    const p2Health = Math.trunc(p2.percent!);
1✔
55
    if (p1Health < p2Health) {
1!
56
      return [{ playerIndex: p1.playerIndex!, position: 0 }];
1✔
57
    } else if (p2Health < p1Health) {
×
58
      return [{ playerIndex: p2.playerIndex!, position: 0 }];
×
59
    }
60

61
    // If stocks and percents were tied, no winner
62
    return [];
×
63
  }
64

65
  const firstPosition = placements.find((placement) => placement.position === 0);
4✔
66
  if (!firstPosition) {
2!
67
    return [];
×
68
  }
69

70
  const winningTeam = players.find(({ playerIndex }) => playerIndex === firstPosition.playerIndex)?.teamId;
4!
71
  if (isTeams && exists(winningTeam)) {
2✔
72
    return placements.filter((placement) => {
1✔
73
      const teamId = players.find(({ playerIndex }) => playerIndex === placement.playerIndex)?.teamId;
10!
74
      return teamId === winningTeam;
4✔
75
    });
76
  }
77

78
  return [firstPosition];
1✔
79
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc