diff --git a/match_collector/champion_stat.ts b/match_collector/champion_stat.ts index a7e2afb..d3b865b 100644 --- a/match_collector/champion_stat.ts +++ b/match_collector/champion_stat.ts @@ -11,6 +11,7 @@ import { areTreeSimilars, treeDeriveTags } from './item_tree' +import { PLATFORM_KEYS } from './platform' import { Match, Timeline, Participant, Frame } from './api' @@ -345,10 +346,10 @@ function handleMatch(match: Match, champions: Map, platfor // Track region distribution for this lane if (lane.regionDistribution && platform) { const platformKey = platform.toLowerCase() - if (platformKey === 'euw1') lane.regionDistribution.euw++ - else if (platformKey === 'eun1') lane.regionDistribution.eun++ - else if (platformKey === 'na1') lane.regionDistribution.na++ - else if (platformKey === 'kr') lane.regionDistribution.kr++ + const regionKey = PLATFORM_KEYS[platformKey] + if (regionKey) { + lane.regionDistribution[regionKey]!++ + } } // Initialize matchups if not present diff --git a/match_collector/index.ts b/match_collector/index.ts index 0bb97a8..16f181f 100644 --- a/match_collector/index.ts +++ b/match_collector/index.ts @@ -5,22 +5,7 @@ import { MongoClient } from 'mongodb' import champion_stat from './champion_stat' import { Match } from './api' - -// Region configuration: platform -> regional routing value -const PLATFORMS: Record = { - 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` -} +import { PLATFORMS, getPlatformBaseUrl, getRegionalBaseUrl, getRegionForPlatform } from './platform' main() @@ -75,7 +60,7 @@ async function main() { // Determine region from matchId (format: PLATFORM_matchId) // Map platform prefix to regional routing value for match API const matchPlatformPrefix = game.split('_')[0] - const matchRegion = PLATFORMS[matchPlatformPrefix] || region + const matchRegion = getRegionForPlatform(matchPlatformPrefix) || region const gameMatch = await match(game, matchRegion) const gameTimeline = await matchTimeline(game, matchRegion) gameMatch.timeline = gameTimeline diff --git a/match_collector/item_tree.ts b/match_collector/item_tree.ts index 7caef09..6272ee5 100644 --- a/match_collector/item_tree.ts +++ b/match_collector/item_tree.ts @@ -1,11 +1,12 @@ -type GoldAdvantageTag = 'ahead' | 'behind' | 'even' +import { + PlatformCounts, + REGION_KEYS, + initPlatformCounts, + mergePlatformCounts, + singlePlatformCount +} from './platform' -type PlatformCounts = { - euw: number - eun: number - na: number - kr: number -} +type GoldAdvantageTag = 'ahead' | 'behind' | 'even' // Item tags that can be derived from purchase patterns type ItemTag = 'ahead' | 'behind' | 'region_euw' | 'region_eun' | 'region_na' | 'region_kr' @@ -30,10 +31,6 @@ type ItemTree = { tags: Array } -function initPlatformCounts(): PlatformCounts { - return { euw: 0, eun: 0, na: 0, kr: 0 } -} - function treeInit(): ItemTree { return { data: undefined, @@ -63,10 +60,7 @@ function nodeMerge(itemtree: ItemTree, node: ItemTree) { child.boughtWhen.behindCount += node.boughtWhen.behindCount // Merge platform counts - child.platformCount.euw += node.platformCount.euw - child.platformCount.eun += node.platformCount.eun - child.platformCount.na += node.platformCount.na - child.platformCount.kr += node.platformCount.kr + mergePlatformCounts(child.platformCount, node.platformCount) next = child break @@ -99,7 +93,6 @@ function treeMerge( let current = itemtree for (const item of items) { - const platformKey = item.platform ? item.platform.toLowerCase() : null current = nodeMerge(current, { data: item.itemId, count: 1, @@ -110,12 +103,7 @@ function treeMerge( meanGold: 0 }, children: [], - platformCount: { - euw: platformKey === 'euw1' ? 1 : 0, - eun: platformKey === 'eun1' ? 1 : 0, - na: platformKey === 'na1' ? 1 : 0, - kr: platformKey === 'kr' ? 1 : 0 - }, + platformCount: item.platform ? singlePlatformCount(item.platform) : initPlatformCounts(), tags: [] }) } @@ -174,12 +162,7 @@ function treeClone(tree: ItemTree): ItemTree { evenCount: tree.boughtWhen.evenCount, meanGold: tree.boughtWhen.meanGold }, - platformCount: { - euw: tree.platformCount.euw, - eun: tree.platformCount.eun, - na: tree.platformCount.na, - kr: tree.platformCount.kr - }, + platformCount: { ...tree.platformCount }, tags: [...tree.tags] } } @@ -192,10 +175,7 @@ function treeMergeTree(t1: ItemTree, t2: ItemTree): ItemTree { t1.count += t2.count // Merge platform counts - t1.platformCount.euw += t2.platformCount.euw - t1.platformCount.eun += t2.platformCount.eun - t1.platformCount.na += t2.platformCount.na - t1.platformCount.kr += t2.platformCount.kr + mergePlatformCounts(t1.platformCount, t2.platformCount) // Merge boughtWhen t1.boughtWhen.aheadCount += t2.boughtWhen.aheadCount @@ -302,44 +282,31 @@ function deriveTags(node: ItemTree, expectedRegionDistribution?: PlatformCounts) } // Derive region tags by comparing against expected distribution - const totalRegionCount = - node.platformCount.euw + node.platformCount.eun + node.platformCount.na + node.platformCount.kr + const totalRegionCount = REGION_KEYS.reduce((sum, key) => sum + node.platformCount[key], 0) if (totalRegionCount > 0 && expectedRegionDistribution) { - const totalExpected = - expectedRegionDistribution.euw + - expectedRegionDistribution.eun + - expectedRegionDistribution.na + - expectedRegionDistribution.kr + const totalExpected = REGION_KEYS.reduce((sum, key) => sum + expectedRegionDistribution[key], 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) // and has a minimum absolute percentage (>= 10%) const SIGNIFICANCE_THRESHOLD = 1.5 const MINIMUM_PCT = 0.1 - if (actualEuwPct >= expectedEuwPct * SIGNIFICANCE_THRESHOLD && actualEuwPct >= MINIMUM_PCT) { - tags.push('region_euw') - } - if (actualEunPct >= expectedEunPct * SIGNIFICANCE_THRESHOLD && actualEunPct >= MINIMUM_PCT) { - tags.push('region_eun') - } - if (actualNaPct >= expectedNaPct * SIGNIFICANCE_THRESHOLD && actualNaPct >= MINIMUM_PCT) { - tags.push('region_na') - } - if (actualKrPct >= expectedKrPct * SIGNIFICANCE_THRESHOLD && actualKrPct >= MINIMUM_PCT) { - tags.push('region_kr') + // Loop through all regions to derive tags + const regionTags: Array<{ key: keyof PlatformCounts; tag: ItemTag }> = [ + { key: 'euw', tag: 'region_euw' }, + { key: 'eun', tag: 'region_eun' }, + { key: 'na', tag: 'region_na' }, + { key: 'kr', tag: 'region_kr' } + ] + + for (const { key, tag } of regionTags) { + const expectedPct = expectedRegionDistribution[key] / totalExpected + const actualPct = node.platformCount[key] / totalRegionCount + + if (actualPct >= expectedPct * SIGNIFICANCE_THRESHOLD && actualPct >= MINIMUM_PCT) { + tags.push(tag) + } } } } diff --git a/match_collector/platform.ts b/match_collector/platform.ts new file mode 100644 index 0000000..7808043 --- /dev/null +++ b/match_collector/platform.ts @@ -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 = { + 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 = { + euw1: 'euw', + eun1: 'eun', + na1: 'na', + kr: 'kr' +} + +// List of all region keys for iteration +const REGION_KEYS: Array = ['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 +}