Multiple changes
- backend: add summoner spells - backend: add build variants - backend: builds are now storing full tree with runes (keystones) - backend: build trees are split on starter items and merged on runes - frontend: computing core tree now - frontend: variant selectors
This commit is contained in:
@@ -81,4 +81,97 @@ function treeSort(itemtree: ItemTree) {
|
||||
}
|
||||
}
|
||||
|
||||
export { ItemTree, treeMerge, treeInit, treeCutBranches, treeSort }
|
||||
/*
|
||||
* Deep clone an ItemTree
|
||||
*/
|
||||
function treeClone(tree: ItemTree): ItemTree {
|
||||
return {
|
||||
data: tree.data,
|
||||
count: tree.count,
|
||||
children: tree.children.map(child => treeClone(child))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge two ItemTrees into one
|
||||
*/
|
||||
function treeMergeTree(t1: ItemTree, t2: ItemTree): ItemTree {
|
||||
// Merge counts for the root
|
||||
t1.count += t2.count
|
||||
|
||||
// Merge children from t2 into t1
|
||||
for (const child2 of t2.children) {
|
||||
// Find matching child in t1 (same data value)
|
||||
const matchingChild = t1.children.find(child1 => child1.data === child2.data)
|
||||
|
||||
if (matchingChild) {
|
||||
// Recursively merge matching children
|
||||
treeMergeTree(matchingChild, child2)
|
||||
} else {
|
||||
// Add a deep copy of child2 to t1
|
||||
t1.children.push(treeClone(child2))
|
||||
}
|
||||
}
|
||||
|
||||
return t1
|
||||
}
|
||||
|
||||
/*
|
||||
* Flatten an ItemTree into a Set of item numbers
|
||||
*/
|
||||
function treeToSet(itemtree: ItemTree): Set<number> {
|
||||
const items: Set<number> = new Set()
|
||||
|
||||
function traverse(node: ItemTree) {
|
||||
if (node.data !== undefined) {
|
||||
items.add(node.data)
|
||||
}
|
||||
for (const child of node.children) {
|
||||
traverse(child)
|
||||
}
|
||||
}
|
||||
|
||||
traverse(itemtree)
|
||||
return items
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate similarity between two trees as item sets.
|
||||
* Returns a number between 0 and 1, where 1 means identical and 0 means completely different.
|
||||
* Uses Jaccard similarity: |A ∩ B| / |A ∪ B|
|
||||
* Sets included in one another will have similarity close to 1.
|
||||
*/
|
||||
function areTreeSimilars(t1: ItemTree, t2: ItemTree): number {
|
||||
const set1 = treeToSet(t1)
|
||||
const set2 = treeToSet(t2)
|
||||
|
||||
// Handle empty sets
|
||||
if (set1.size === 0 && set2.size === 0) {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// Calculate intersection
|
||||
const intersection = new Set<number>()
|
||||
for (const item of Array.from(set1)) {
|
||||
if (set2.has(item)) {
|
||||
intersection.add(item)
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate union
|
||||
const union = new Set<number>()
|
||||
for (const item of Array.from(set1)) {
|
||||
union.add(item)
|
||||
}
|
||||
for (const item of Array.from(set2)) {
|
||||
union.add(item)
|
||||
}
|
||||
|
||||
// Jaccard similarity: |intersection| / |union|
|
||||
const similarity = intersection.size / Math.min(set1.size, set2.size)
|
||||
|
||||
// Ensure result is between 0 and 1
|
||||
return Math.max(0, Math.min(1, similarity))
|
||||
}
|
||||
|
||||
export { ItemTree, treeMerge, treeInit, treeCutBranches, treeSort, treeMergeTree, areTreeSimilars }
|
||||
|
||||
Reference in New Issue
Block a user