refactor/match_collector: refactor platform handling logic
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
|||||||
areTreeSimilars,
|
areTreeSimilars,
|
||||||
treeDeriveTags
|
treeDeriveTags
|
||||||
} from './item_tree'
|
} from './item_tree'
|
||||||
|
import { PLATFORM_KEYS } from './platform'
|
||||||
|
|
||||||
import { Match, Timeline, Participant, Frame } from './api'
|
import { Match, Timeline, Participant, Frame } from './api'
|
||||||
|
|
||||||
@@ -345,10 +346,10 @@ function handleMatch(match: Match, champions: Map<number, ChampionData>, platfor
|
|||||||
// Track region distribution for this lane
|
// Track region distribution for this lane
|
||||||
if (lane.regionDistribution && platform) {
|
if (lane.regionDistribution && platform) {
|
||||||
const platformKey = platform.toLowerCase()
|
const platformKey = platform.toLowerCase()
|
||||||
if (platformKey === 'euw1') lane.regionDistribution.euw++
|
const regionKey = PLATFORM_KEYS[platformKey]
|
||||||
else if (platformKey === 'eun1') lane.regionDistribution.eun++
|
if (regionKey) {
|
||||||
else if (platformKey === 'na1') lane.regionDistribution.na++
|
lane.regionDistribution[regionKey]!++
|
||||||
else if (platformKey === 'kr') lane.regionDistribution.kr++
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize matchups if not present
|
// Initialize matchups if not present
|
||||||
|
|||||||
@@ -5,22 +5,7 @@ import { MongoClient } from 'mongodb'
|
|||||||
|
|
||||||
import champion_stat from './champion_stat'
|
import champion_stat from './champion_stat'
|
||||||
import { Match } from './api'
|
import { Match } from './api'
|
||||||
|
import { PLATFORMS, getPlatformBaseUrl, getRegionalBaseUrl, getRegionForPlatform } from './platform'
|
||||||
// Region configuration: platform -> regional routing value
|
|
||||||
const PLATFORMS: Record<string, string> = {
|
|
||||||
EUW1: 'EUROPE',
|
|
||||||
EUN1: 'EUROPE',
|
|
||||||
NA1: 'AMERICAS',
|
|
||||||
KR: 'ASIA'
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPlatformBaseUrl(platform: string): string {
|
|
||||||
return `https://${platform.toLowerCase()}.api.riotgames.com`
|
|
||||||
}
|
|
||||||
|
|
||||||
function getRegionalBaseUrl(region: string): string {
|
|
||||||
return `https://${region.toLowerCase()}.api.riotgames.com`
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
@@ -75,7 +60,7 @@ async function main() {
|
|||||||
// Determine region from matchId (format: PLATFORM_matchId)
|
// Determine region from matchId (format: PLATFORM_matchId)
|
||||||
// Map platform prefix to regional routing value for match API
|
// Map platform prefix to regional routing value for match API
|
||||||
const matchPlatformPrefix = game.split('_')[0]
|
const matchPlatformPrefix = game.split('_')[0]
|
||||||
const matchRegion = PLATFORMS[matchPlatformPrefix] || region
|
const matchRegion = getRegionForPlatform(matchPlatformPrefix) || region
|
||||||
const gameMatch = await match(game, matchRegion)
|
const gameMatch = await match(game, matchRegion)
|
||||||
const gameTimeline = await matchTimeline(game, matchRegion)
|
const gameTimeline = await matchTimeline(game, matchRegion)
|
||||||
gameMatch.timeline = gameTimeline
|
gameMatch.timeline = gameTimeline
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
type GoldAdvantageTag = 'ahead' | 'behind' | 'even'
|
import {
|
||||||
|
PlatformCounts,
|
||||||
|
REGION_KEYS,
|
||||||
|
initPlatformCounts,
|
||||||
|
mergePlatformCounts,
|
||||||
|
singlePlatformCount
|
||||||
|
} from './platform'
|
||||||
|
|
||||||
type PlatformCounts = {
|
type GoldAdvantageTag = 'ahead' | 'behind' | 'even'
|
||||||
euw: number
|
|
||||||
eun: number
|
|
||||||
na: number
|
|
||||||
kr: number
|
|
||||||
}
|
|
||||||
|
|
||||||
// Item tags that can be derived from purchase patterns
|
// Item tags that can be derived from purchase patterns
|
||||||
type ItemTag = 'ahead' | 'behind' | 'region_euw' | 'region_eun' | 'region_na' | 'region_kr'
|
type ItemTag = 'ahead' | 'behind' | 'region_euw' | 'region_eun' | 'region_na' | 'region_kr'
|
||||||
@@ -30,10 +31,6 @@ type ItemTree = {
|
|||||||
tags: Array<ItemTag>
|
tags: Array<ItemTag>
|
||||||
}
|
}
|
||||||
|
|
||||||
function initPlatformCounts(): PlatformCounts {
|
|
||||||
return { euw: 0, eun: 0, na: 0, kr: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
function treeInit(): ItemTree {
|
function treeInit(): ItemTree {
|
||||||
return {
|
return {
|
||||||
data: undefined,
|
data: undefined,
|
||||||
@@ -63,10 +60,7 @@ function nodeMerge(itemtree: ItemTree, node: ItemTree) {
|
|||||||
child.boughtWhen.behindCount += node.boughtWhen.behindCount
|
child.boughtWhen.behindCount += node.boughtWhen.behindCount
|
||||||
|
|
||||||
// Merge platform counts
|
// Merge platform counts
|
||||||
child.platformCount.euw += node.platformCount.euw
|
mergePlatformCounts(child.platformCount, node.platformCount)
|
||||||
child.platformCount.eun += node.platformCount.eun
|
|
||||||
child.platformCount.na += node.platformCount.na
|
|
||||||
child.platformCount.kr += node.platformCount.kr
|
|
||||||
|
|
||||||
next = child
|
next = child
|
||||||
break
|
break
|
||||||
@@ -99,7 +93,6 @@ function treeMerge(
|
|||||||
let current = itemtree
|
let current = itemtree
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const platformKey = item.platform ? item.platform.toLowerCase() : null
|
|
||||||
current = nodeMerge(current, {
|
current = nodeMerge(current, {
|
||||||
data: item.itemId,
|
data: item.itemId,
|
||||||
count: 1,
|
count: 1,
|
||||||
@@ -110,12 +103,7 @@ function treeMerge(
|
|||||||
meanGold: 0
|
meanGold: 0
|
||||||
},
|
},
|
||||||
children: [],
|
children: [],
|
||||||
platformCount: {
|
platformCount: item.platform ? singlePlatformCount(item.platform) : initPlatformCounts(),
|
||||||
euw: platformKey === 'euw1' ? 1 : 0,
|
|
||||||
eun: platformKey === 'eun1' ? 1 : 0,
|
|
||||||
na: platformKey === 'na1' ? 1 : 0,
|
|
||||||
kr: platformKey === 'kr' ? 1 : 0
|
|
||||||
},
|
|
||||||
tags: []
|
tags: []
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -174,12 +162,7 @@ function treeClone(tree: ItemTree): ItemTree {
|
|||||||
evenCount: tree.boughtWhen.evenCount,
|
evenCount: tree.boughtWhen.evenCount,
|
||||||
meanGold: tree.boughtWhen.meanGold
|
meanGold: tree.boughtWhen.meanGold
|
||||||
},
|
},
|
||||||
platformCount: {
|
platformCount: { ...tree.platformCount },
|
||||||
euw: tree.platformCount.euw,
|
|
||||||
eun: tree.platformCount.eun,
|
|
||||||
na: tree.platformCount.na,
|
|
||||||
kr: tree.platformCount.kr
|
|
||||||
},
|
|
||||||
tags: [...tree.tags]
|
tags: [...tree.tags]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,10 +175,7 @@ function treeMergeTree(t1: ItemTree, t2: ItemTree): ItemTree {
|
|||||||
t1.count += t2.count
|
t1.count += t2.count
|
||||||
|
|
||||||
// Merge platform counts
|
// Merge platform counts
|
||||||
t1.platformCount.euw += t2.platformCount.euw
|
mergePlatformCounts(t1.platformCount, t2.platformCount)
|
||||||
t1.platformCount.eun += t2.platformCount.eun
|
|
||||||
t1.platformCount.na += t2.platformCount.na
|
|
||||||
t1.platformCount.kr += t2.platformCount.kr
|
|
||||||
|
|
||||||
// Merge boughtWhen
|
// Merge boughtWhen
|
||||||
t1.boughtWhen.aheadCount += t2.boughtWhen.aheadCount
|
t1.boughtWhen.aheadCount += t2.boughtWhen.aheadCount
|
||||||
@@ -302,44 +282,31 @@ function deriveTags(node: ItemTree, expectedRegionDistribution?: PlatformCounts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Derive region tags by comparing against expected distribution
|
// Derive region tags by comparing against expected distribution
|
||||||
const totalRegionCount =
|
const totalRegionCount = REGION_KEYS.reduce((sum, key) => sum + node.platformCount[key], 0)
|
||||||
node.platformCount.euw + node.platformCount.eun + node.platformCount.na + node.platformCount.kr
|
|
||||||
if (totalRegionCount > 0 && expectedRegionDistribution) {
|
if (totalRegionCount > 0 && expectedRegionDistribution) {
|
||||||
const totalExpected =
|
const totalExpected = REGION_KEYS.reduce((sum, key) => sum + expectedRegionDistribution[key], 0)
|
||||||
expectedRegionDistribution.euw +
|
|
||||||
expectedRegionDistribution.eun +
|
|
||||||
expectedRegionDistribution.na +
|
|
||||||
expectedRegionDistribution.kr
|
|
||||||
|
|
||||||
if (totalExpected > 0) {
|
if (totalExpected > 0) {
|
||||||
// Calculate expected percentages
|
|
||||||
const expectedEuwPct = expectedRegionDistribution.euw / totalExpected
|
|
||||||
const expectedEunPct = expectedRegionDistribution.eun / totalExpected
|
|
||||||
const expectedNaPct = expectedRegionDistribution.na / totalExpected
|
|
||||||
const expectedKrPct = expectedRegionDistribution.kr / totalExpected
|
|
||||||
|
|
||||||
// Calculate actual percentages for this item
|
|
||||||
const actualEuwPct = node.platformCount.euw / totalRegionCount
|
|
||||||
const actualEunPct = node.platformCount.eun / totalRegionCount
|
|
||||||
const actualNaPct = node.platformCount.na / totalRegionCount
|
|
||||||
const actualKrPct = node.platformCount.kr / totalRegionCount
|
|
||||||
|
|
||||||
// Tag if the item is significantly more popular in a region (>= 1.5x expected rate)
|
// Tag if the item is significantly more popular in a region (>= 1.5x expected rate)
|
||||||
// and has a minimum absolute percentage (>= 10%)
|
// and has a minimum absolute percentage (>= 10%)
|
||||||
const SIGNIFICANCE_THRESHOLD = 1.5
|
const SIGNIFICANCE_THRESHOLD = 1.5
|
||||||
const MINIMUM_PCT = 0.1
|
const MINIMUM_PCT = 0.1
|
||||||
|
|
||||||
if (actualEuwPct >= expectedEuwPct * SIGNIFICANCE_THRESHOLD && actualEuwPct >= MINIMUM_PCT) {
|
// Loop through all regions to derive tags
|
||||||
tags.push('region_euw')
|
const regionTags: Array<{ key: keyof PlatformCounts; tag: ItemTag }> = [
|
||||||
}
|
{ key: 'euw', tag: 'region_euw' },
|
||||||
if (actualEunPct >= expectedEunPct * SIGNIFICANCE_THRESHOLD && actualEunPct >= MINIMUM_PCT) {
|
{ key: 'eun', tag: 'region_eun' },
|
||||||
tags.push('region_eun')
|
{ key: 'na', tag: 'region_na' },
|
||||||
}
|
{ key: 'kr', tag: 'region_kr' }
|
||||||
if (actualNaPct >= expectedNaPct * SIGNIFICANCE_THRESHOLD && actualNaPct >= MINIMUM_PCT) {
|
]
|
||||||
tags.push('region_na')
|
|
||||||
}
|
for (const { key, tag } of regionTags) {
|
||||||
if (actualKrPct >= expectedKrPct * SIGNIFICANCE_THRESHOLD && actualKrPct >= MINIMUM_PCT) {
|
const expectedPct = expectedRegionDistribution[key] / totalExpected
|
||||||
tags.push('region_kr')
|
const actualPct = node.platformCount[key] / totalRegionCount
|
||||||
|
|
||||||
|
if (actualPct >= expectedPct * SIGNIFICANCE_THRESHOLD && actualPct >= MINIMUM_PCT) {
|
||||||
|
tags.push(tag)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
104
match_collector/platform.ts
Normal file
104
match_collector/platform.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* Platform and region configuration for Riot Games API
|
||||||
|
*
|
||||||
|
* Platforms are the server clusters (EUW1, EUN1, NA1, KR)
|
||||||
|
* Regions are the routing values for match API (EUROPE, AMERICAS, ASIA)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Platform to regional routing value mapping
|
||||||
|
const PLATFORMS: Record<string, string> = {
|
||||||
|
EUW1: 'EUROPE',
|
||||||
|
EUN1: 'EUROPE',
|
||||||
|
NA1: 'AMERICAS',
|
||||||
|
KR: 'ASIA'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform counts for tracking item purchases per region
|
||||||
|
type PlatformCounts = {
|
||||||
|
euw: number
|
||||||
|
eun: number
|
||||||
|
na: number
|
||||||
|
kr: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform key mapping for converting platform strings to PlatformCounts keys
|
||||||
|
const PLATFORM_KEYS: Record<string, keyof PlatformCounts> = {
|
||||||
|
euw1: 'euw',
|
||||||
|
eun1: 'eun',
|
||||||
|
na1: 'na',
|
||||||
|
kr: 'kr'
|
||||||
|
}
|
||||||
|
|
||||||
|
// List of all region keys for iteration
|
||||||
|
const REGION_KEYS: Array<keyof PlatformCounts> = ['euw', 'eun', 'na', 'kr']
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the base URL for platform-specific API calls (e.g., league-v4)
|
||||||
|
*/
|
||||||
|
function getPlatformBaseUrl(platform: string): string {
|
||||||
|
return `https://${platform.toLowerCase()}.api.riotgames.com`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the base URL for regional API calls (e.g., match-v5)
|
||||||
|
*/
|
||||||
|
function getRegionalBaseUrl(region: string): string {
|
||||||
|
return `https://${region.toLowerCase()}.api.riotgames.com`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the regional routing value for a platform
|
||||||
|
* Falls back to the provided default region if platform not found
|
||||||
|
*/
|
||||||
|
function getRegionForPlatform(platform: string): string | undefined {
|
||||||
|
return PLATFORMS[platform]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an empty PlatformCounts object
|
||||||
|
*/
|
||||||
|
function initPlatformCounts(): PlatformCounts {
|
||||||
|
return { euw: 0, eun: 0, na: 0, kr: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge platform counts from source into target
|
||||||
|
*/
|
||||||
|
function mergePlatformCounts(target: PlatformCounts, source: PlatformCounts): void {
|
||||||
|
for (const key of REGION_KEYS) {
|
||||||
|
target[key] += source[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a platform count with a single platform set to 1
|
||||||
|
*/
|
||||||
|
function singlePlatformCount(platform: string): PlatformCounts {
|
||||||
|
const counts = initPlatformCounts()
|
||||||
|
const key = PLATFORM_KEYS[platform.toLowerCase()]
|
||||||
|
if (key) {
|
||||||
|
counts[key] = 1
|
||||||
|
}
|
||||||
|
return counts
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the PlatformCounts key for a platform string
|
||||||
|
*/
|
||||||
|
function getPlatformKey(platform: string): keyof PlatformCounts | undefined {
|
||||||
|
return PLATFORM_KEYS[platform.toLowerCase()]
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
PLATFORMS,
|
||||||
|
PlatformCounts,
|
||||||
|
PLATFORM_KEYS,
|
||||||
|
REGION_KEYS,
|
||||||
|
getPlatformBaseUrl,
|
||||||
|
getRegionalBaseUrl,
|
||||||
|
getRegionForPlatform,
|
||||||
|
initPlatformCounts,
|
||||||
|
mergePlatformCounts,
|
||||||
|
singlePlatformCount,
|
||||||
|
getPlatformKey
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user