match_collector: track gold advantage when items are bought
also add api.ts with Riot API types
This commit is contained in:
@@ -1,14 +1,7 @@
|
||||
function sameArrays(array1: Array<number>, array2: Array<number>) {
|
||||
if (array1.length != array2.length) return false
|
||||
for (const e of array1) {
|
||||
if (!array2.includes(e)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
import { MongoClient } from 'mongodb'
|
||||
import {
|
||||
ItemTree,
|
||||
GoldAdvantageTag,
|
||||
treeInit,
|
||||
treeMerge,
|
||||
treeCutBranches,
|
||||
@@ -16,6 +9,16 @@ import {
|
||||
treeMergeTree,
|
||||
areTreeSimilars
|
||||
} from './item_tree'
|
||||
|
||||
import { Match, Timeline, Participant, Frame } from './api'
|
||||
|
||||
function sameArrays(array1: Array<number>, array2: Array<number>) {
|
||||
if (array1.length != array2.length) return false
|
||||
for (const e of array1) {
|
||||
if (!array2.includes(e)) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
const itemDict = new Map()
|
||||
|
||||
async function itemList() {
|
||||
@@ -107,8 +110,7 @@ type ChampionData = {
|
||||
}
|
||||
|
||||
// Helper function to create rune configuration from participant
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function createRuneConfiguration(participant: any): Rune {
|
||||
function createRuneConfiguration(participant: Participant): Rune {
|
||||
const primaryStyle = participant.perks.styles[0].style
|
||||
const secondaryStyle = participant.perks.styles[1].style
|
||||
const selections: Array<number> = []
|
||||
@@ -126,8 +128,7 @@ function createRuneConfiguration(participant: any): Rune {
|
||||
}
|
||||
|
||||
// Find or create a build for the given rune keystone
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function findOrCreateBuild(builds: Builds, participant: any): Build {
|
||||
function findOrCreateBuild(builds: Builds, participant: Participant): Build {
|
||||
const keystone = participant.perks.styles[0].selections[0].perk
|
||||
const runeConfig = createRuneConfiguration(participant)
|
||||
|
||||
@@ -166,24 +167,71 @@ function findOrCreateBuild(builds: Builds, participant: any): Build {
|
||||
return newBuild
|
||||
}
|
||||
|
||||
// Calculate gold advantage at the time of item purchase
|
||||
// Returns 'ahead', 'behind', or 'even' based on gold difference
|
||||
function calculateGoldAdvantage(
|
||||
match: Match,
|
||||
frame: Frame,
|
||||
participantIndex: number
|
||||
): GoldAdvantageTag {
|
||||
const GOLD_THRESHOLD = 1000 // 1000 gold difference threshold
|
||||
|
||||
const participantFrames = [
|
||||
frame.participantFrames[1],
|
||||
frame.participantFrames[2],
|
||||
frame.participantFrames[3],
|
||||
frame.participantFrames[4],
|
||||
frame.participantFrames[5],
|
||||
frame.participantFrames[6],
|
||||
frame.participantFrames[7],
|
||||
frame.participantFrames[8],
|
||||
frame.participantFrames[9],
|
||||
frame.participantFrames[10]
|
||||
]
|
||||
|
||||
// Find the participant's team
|
||||
const participantFrame = participantFrames[participantIndex - 1]
|
||||
const participantGold = participantFrame.totalGold
|
||||
if (!participantFrame) return 'even'
|
||||
|
||||
const participant = match.info.participants.find(
|
||||
x => x.participantId == participantFrame.participantId
|
||||
)!
|
||||
|
||||
const opponent = match.info.participants.find(
|
||||
x => x.teamPosition === participant.teamPosition && x.teamId != participant.teamId
|
||||
)
|
||||
if (opponent == undefined) return 'even'
|
||||
|
||||
const opponentGold = participantFrames.find(
|
||||
x => x.participantId == opponent.participantId
|
||||
)!.totalGold
|
||||
|
||||
const goldDiff = participantGold - opponentGold
|
||||
|
||||
if (goldDiff >= GOLD_THRESHOLD) return 'ahead'
|
||||
if (goldDiff <= -GOLD_THRESHOLD) return 'behind'
|
||||
return 'even'
|
||||
}
|
||||
|
||||
function handleMatchBuilds(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
timeline: any,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
participant: any,
|
||||
match: Match,
|
||||
participant: Participant,
|
||||
participantIndex: number,
|
||||
builds: Builds
|
||||
) {
|
||||
const timeline: Timeline = match.timeline
|
||||
|
||||
// Find or create the build for this participant's rune configuration
|
||||
const build = findOrCreateBuild(builds, participant)
|
||||
build.count += 1
|
||||
|
||||
const items: Array<number> = []
|
||||
const items: Array<{ itemId: number; goldAdvantage: GoldAdvantageTag }> = []
|
||||
for (const frame of timeline.info.frames) {
|
||||
for (const event of frame.events) {
|
||||
if (event.participantId != participantIndex) continue
|
||||
if (event.type == 'ITEM_UNDO') {
|
||||
if (items.length > 0 && items[items.length - 1] == event.beforeId) {
|
||||
if (items.length > 0 && items[items.length - 1].itemId == event.beforeId) {
|
||||
items.pop()
|
||||
}
|
||||
continue
|
||||
@@ -251,7 +299,9 @@ function handleMatchBuilds(
|
||||
if (itemInfo.to.length != 0 && (items.length >= 1 || participant.teamPosition === 'UTILITY'))
|
||||
continue
|
||||
|
||||
items.push(event.itemId)
|
||||
// Calculate gold advantage at time of purchase
|
||||
const goldAdvantage = calculateGoldAdvantage(match, frame, participantIndex)
|
||||
items.push({ itemId: event.itemId, goldAdvantage })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,13 +312,12 @@ function handleMatchBuilds(
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function handleMatch(match: any, champions: Map<number, ChampionData>) {
|
||||
function handleMatch(match: Match, champions: Map<number, ChampionData>) {
|
||||
let participantIndex = 0
|
||||
for (const participant of match.info.participants) {
|
||||
participantIndex += 1
|
||||
const championId = participant.championId
|
||||
const champion = champions.get(championId)
|
||||
const champion = champions.get(championId)!
|
||||
|
||||
// Lanes
|
||||
let lane = champion.lanes.find(x => x.data == participant.teamPosition)
|
||||
@@ -333,7 +382,7 @@ function handleMatch(match: any, champions: Map<number, ChampionData>) {
|
||||
matchup.winrate = (matchup.winrate * (matchup.games - 1)) / matchup.games
|
||||
}
|
||||
} else {
|
||||
const opponentChampion = champions.get(opponentChampionId)
|
||||
const opponentChampion = champions.get(opponentChampionId)!
|
||||
|
||||
lane.matchups.push({
|
||||
championId: opponentChampionId,
|
||||
@@ -346,7 +395,7 @@ function handleMatch(match: any, champions: Map<number, ChampionData>) {
|
||||
}
|
||||
|
||||
// Items and runes (builds)
|
||||
handleMatchBuilds(match.timeline, participant, participantIndex, lane.builds)
|
||||
handleMatchBuilds(match, participant, participantIndex, lane.builds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +415,7 @@ async function handleMatchList(
|
||||
'\rComputing champion stats, game entry ' + currentMatch + '/' + totalMatches + ' ... '
|
||||
)
|
||||
currentMatch += 1
|
||||
handleMatch(match, champions)
|
||||
handleMatch(match as unknown as Match, champions)
|
||||
}
|
||||
|
||||
return totalMatches
|
||||
@@ -389,10 +438,10 @@ function splitMergeOnStarterItem(build: Build, championName: string): BuildWithS
|
||||
) {
|
||||
const startItems = []
|
||||
let items = build.items.children[0]
|
||||
startItems.push({ data: build.items.children[0].data, count: build.items.children[0].count })
|
||||
startItems.push({ data: build.items.children[0].data!, count: build.items.children[0].count })
|
||||
build.items.children[0].data = undefined
|
||||
if (build.items.children.length > 1) {
|
||||
startItems.push({ data: build.items.children[1].data, count: build.items.children[1].count })
|
||||
startItems.push({ data: build.items.children[1].data!, count: build.items.children[1].count })
|
||||
build.items.children[1].data = undefined
|
||||
items = treeMergeTree(build.items.children[0], build.items.children[1])
|
||||
}
|
||||
@@ -420,7 +469,7 @@ function splitMergeOnStarterItem(build: Build, championName: string): BuildWithS
|
||||
items: c,
|
||||
bootsFirstCount: build.bootsFirstCount,
|
||||
count: c.count,
|
||||
startItems: [{ data: c.data, count: c.count }],
|
||||
startItems: [{ data: c.data!, count: c.count }],
|
||||
suppItems: build.suppItems,
|
||||
boots: build.boots
|
||||
})
|
||||
@@ -567,7 +616,7 @@ async function finalizeChampionStats(champion: ChampionData, totalMatches: numbe
|
||||
// Summoner spells
|
||||
lane.summonerSpells.forEach(x => (x.pickrate = x.count / lane.count))
|
||||
lane.summonerSpells.sort((a, b) => b.count - a.count)
|
||||
lane.summonerSpells = lane.summonerSpells.filter(x => x.pickrate >= 0.05)
|
||||
lane.summonerSpells = lane.summonerSpells.filter(x => x.pickrate! >= 0.05)
|
||||
|
||||
// Cleaning up builds
|
||||
cleanupLaneBuilds(lane)
|
||||
@@ -674,7 +723,7 @@ async function makeChampionsStats(client: MongoClient, patch: string) {
|
||||
const database = client.db('champions')
|
||||
const collection = database.collection(patch)
|
||||
for (const champion of list) {
|
||||
const championInfo = await finalizeChampionStats(champions.get(champion.id), totalMatches)
|
||||
const championInfo = await finalizeChampionStats(champions.get(champion.id)!, totalMatches)
|
||||
await collection.updateOne({ id: champion.id }, { $set: championInfo }, { upsert: true })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user