From bf364bb02c6bf16ff1ce920e191c83c1a8a5a17f Mon Sep 17 00:00:00 2001 From: Taylor Gregory Date: Thu, 25 Jun 2020 22:47:34 -0400 Subject: [PATCH 1/4] Get the players stocks from the slp --- src/stats/overall.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stats/overall.ts b/src/stats/overall.ts index e92467fd..5ad47cbc 100644 --- a/src/stats/overall.ts +++ b/src/stats/overall.ts @@ -32,6 +32,7 @@ export function generateOverallStats( const conversions = _.get(conversionsByPlayer, playerIndex) || []; const successfulConversions = conversions.filter(conversion => conversion.moves.length > 1); const opponentStocks = _.get(stocksByPlayer, opponentIndex) || []; + const playerStocks = _.get(stocksByPlayer, playerIndex); const opponentEndedStocks = _.filter(opponentStocks, 'endFrame'); const conversionCount = conversions.length; From 244ffd0a0ef78cb3494413c33da700007c857afe Mon Sep 17 00:00:00 2001 From: Taylor Gregory Date: Thu, 25 Jun 2020 23:00:21 -0400 Subject: [PATCH 2/4] Address fix me --- src/stats/stocks.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/stats/stocks.ts b/src/stats/stocks.ts index e0eec642..1db03ba6 100644 --- a/src/stats/stocks.ts +++ b/src/stats/stocks.ts @@ -3,6 +3,7 @@ import _ from 'lodash'; import { FrameEntryType, FramesType, isDead, didLoseStock, PlayerIndexedType, StockType } from "./common"; import { StatComputer } from './stats'; +import { PostFrameUpdateType } from '../utils/slpReader'; interface StockState { stock: StockType | null | undefined; @@ -38,10 +39,10 @@ export class StockComputer implements StatComputer { function handleStockCompute(frames: FramesType, state: StockState, indices: PlayerIndexedType, frame: FrameEntryType, stocks: StockType[]): void { const playerFrame = frame.players[indices.playerIndex].post; - // FIXME: use PostFrameUpdateType instead of any - const prevPlayerFrame: any = _.get( + + const prevPlayerFrame: PostFrameUpdateType = _.get( frames, [playerFrame.frame - 1, 'players', indices.playerIndex, 'post'], {} - ); + ) as PostFrameUpdateType; // If there is currently no active stock, wait until the player is no longer spawning. // Once the player is no longer spawning, start the stock From 5c728b2042987664958442fcadb63e3e5287b79e Mon Sep 17 00:00:00 2001 From: Taylor Gregory Date: Thu, 25 Jun 2020 23:26:05 -0400 Subject: [PATCH 3/4] Implement method to determine winner based on StockEvents --- src/stats/overall.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/stats/overall.ts b/src/stats/overall.ts index 5ad47cbc..dd1b5921 100644 --- a/src/stats/overall.ts +++ b/src/stats/overall.ts @@ -32,7 +32,7 @@ export function generateOverallStats( const conversions = _.get(conversionsByPlayer, playerIndex) || []; const successfulConversions = conversions.filter(conversion => conversion.moves.length > 1); const opponentStocks = _.get(stocksByPlayer, opponentIndex) || []; - const playerStocks = _.get(stocksByPlayer, playerIndex); + const playerStocks = _.get(stocksByPlayer, playerIndex) || []; const opponentEndedStocks = _.filter(opponentStocks, 'endFrame'); const conversionCount = conversions.length; @@ -48,6 +48,7 @@ export function generateOverallStats( conversionCount: conversionCount, totalDamage: totalDamage, killCount: killCount, + winnerIndex: determineWinner(playerStocks, opponentStocks), successfulConversions: getRatio(successfulConversionCount, conversionCount), inputsPerMinute: getRatio(inputCount, gameMinutes), @@ -68,6 +69,23 @@ export function generateOverallStats( return overall; } +function determineWinner(playerStocks: StockType[], opponentStocks: StockType[]) : number { + + if (playerStocks.length == 0 && opponentStocks.length == 0) return -1; //unknown winner; + + if (playerStocks.length === opponentStocks.length) { + var playerLastStock = playerStocks[playerStocks.length - 1] + var opponentLastStock = opponentStocks[opponentStocks.length - 1]; + + if (playerLastStock.endPercent > opponentLastStock.endPercent) return opponentLastStock.playerIndex; + if (playerLastStock.endPercent < opponentLastStock.endPercent) return playerLastStock.playerIndex; + } + + // More stock events, means more deaths. + if (playerStocks.length > opponentStocks.length) return playerStocks[0].opponentIndex; + if (playerStocks.length < opponentStocks.length) return opponentStocks[0].playerIndex; +} + function getRatio(count: number, total: number): RatioType { return { count: count, From 2aa2ecfaf5fca4e0dd0c3814b93f0552bacd4852 Mon Sep 17 00:00:00 2001 From: Taylor Gregory Date: Fri, 26 Jun 2020 18:52:23 -0400 Subject: [PATCH 4/4] Move logic to slippi game. Operate on StockType[] instead. --- src/SlippiGame.ts | 29 ++++++++++++++++++++++++++++- src/stats/common.ts | 1 + src/stats/overall.ts | 18 ------------------ 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/SlippiGame.ts b/src/SlippiGame.ts index e7888073..df99fd2d 100644 --- a/src/SlippiGame.ts +++ b/src/SlippiGame.ts @@ -13,7 +13,8 @@ import { SlpParser } from './utils/slpParser'; import { StockComputer, ComboComputer, ActionsComputer, ConversionComputer, InputComputer, Stats, FrameEntryType, FramesType, StatsType, getSinglesPlayerPermutationsFromSettings, - generateOverallStats + generateOverallStats, + StockType } from './stats'; /** @@ -147,6 +148,7 @@ export class SlippiGame { actionCounts: this.actionsComputer.fetch(), overall: overall, gameComplete: this.parser.getGameEnd() !== null, + winningPlayerIndex: this.determineWinningPlayerIndex(stocks) }; if (this.parser.getGameEnd() !== null) { @@ -160,6 +162,31 @@ export class SlippiGame { return stats; } + public determineWinningPlayerIndex(stocks: StockType[]): number { + if (stocks.length == 0) return -1; + + var playerIndexOccurences: Array<{playerIndex: number, count: number, lastPercent: number}> = []; + + stocks.forEach(stockType => { + if(!playerIndexOccurences.some(occurences => occurences.playerIndex === stockType.playerIndex)){ + playerIndexOccurences.push({playerIndex: stockType.playerIndex, count: 0, lastPercent: 0}); + } + + var occurence = playerIndexOccurences.find(occurence => occurence.playerIndex == stockType.playerIndex); + occurence.count++; + occurence.lastPercent = stockType.endPercent; + }); + + var sortedByOccurence = _.sortBy(playerIndexOccurences, occurence => occurence.count); + var mostOccurences = sortedByOccurence[sortedByOccurence.length - 1]; + + var matchingOccurences = sortedByOccurence.filter(occurence => occurence.count == mostOccurences.count); + if (matchingOccurences.length == 1) return mostOccurences.playerIndex; + + var sortedByPercent = _.sortBy(playerIndexOccurences, occurence => occurence.lastPercent); + return sortedByPercent[sortedByPercent.length - 1].playerIndex; + } + public getMetadata(): MetadataType { if (this.metadata) { return this.metadata; diff --git a/src/stats/common.ts b/src/stats/common.ts index b4d808a3..e3aa0585 100644 --- a/src/stats/common.ts +++ b/src/stats/common.ts @@ -27,6 +27,7 @@ export type StatsType = { combos: ComboType[]; actionCounts: ActionCountsType[]; overall: OverallType[]; + winningPlayerIndex: number; }; export type RatioType = { diff --git a/src/stats/overall.ts b/src/stats/overall.ts index dd1b5921..49fec252 100644 --- a/src/stats/overall.ts +++ b/src/stats/overall.ts @@ -48,7 +48,6 @@ export function generateOverallStats( conversionCount: conversionCount, totalDamage: totalDamage, killCount: killCount, - winnerIndex: determineWinner(playerStocks, opponentStocks), successfulConversions: getRatio(successfulConversionCount, conversionCount), inputsPerMinute: getRatio(inputCount, gameMinutes), @@ -69,23 +68,6 @@ export function generateOverallStats( return overall; } -function determineWinner(playerStocks: StockType[], opponentStocks: StockType[]) : number { - - if (playerStocks.length == 0 && opponentStocks.length == 0) return -1; //unknown winner; - - if (playerStocks.length === opponentStocks.length) { - var playerLastStock = playerStocks[playerStocks.length - 1] - var opponentLastStock = opponentStocks[opponentStocks.length - 1]; - - if (playerLastStock.endPercent > opponentLastStock.endPercent) return opponentLastStock.playerIndex; - if (playerLastStock.endPercent < opponentLastStock.endPercent) return playerLastStock.playerIndex; - } - - // More stock events, means more deaths. - if (playerStocks.length > opponentStocks.length) return playerStocks[0].opponentIndex; - if (playerStocks.length < opponentStocks.length) return opponentStocks[0].playerIndex; -} - function getRatio(count: number, total: number): RatioType { return { count: count,