UNPKG

data-structure-typed

Version:
741 lines (629 loc) 25.3 kB
import { AVLTreeMultiMap, AVLTreeMultiMapNode } from '../../../../src'; // import { isDebugTest } from '../../../config'; // const isDebug = isDebugTest; describe('AVLTreeMultiMap', () => { let avlTmm: AVLTreeMultiMap<number, number>; beforeEach(() => { avlTmm = new AVLTreeMultiMap<number, number>(); }); it('Should add and delete values', () => { avlTmm.add(3, 3); avlTmm.add(3, 33); avlTmm.add(3, 333); expect(avlTmm.get(3)).toEqual([3, 33, 333]); avlTmm.deleteValue(3, 33); expect(avlTmm.get(3)).toEqual([3, 333]); avlTmm.deleteValue(3, 3); expect(avlTmm.get(3)).toEqual([333]); avlTmm.deleteValue(3, 333); expect(avlTmm.get(3)).toBe(undefined); avlTmm.add(3, 3); avlTmm.add([3, [3333, 33333]]); expect(avlTmm.get(3)).toEqual([3, 3333, 33333]); }); }); describe('AVLTreeMultiMap Test', () => { it('should perform various operations on a AVLTreeMultiMap', () => { const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; const avlTmm = new AVLTreeMultiMap<number>(); for (const i of arr) avlTmm.add([i, [i]]); avlTmm.add(null); const node6 = avlTmm.getNode(6); expect(node6 && avlTmm.getHeight(node6)).toBe(3); expect(node6 && avlTmm.getDepth(node6)).toBe(1); const getNodeById = avlTmm.getNode(10); expect(getNodeById?.key).toBe(10); const getMinNodeByRoot = avlTmm.getLeftMost(); expect(getMinNodeByRoot).toBe(1); const node15 = avlTmm.getNode(15); const getMinNodeBySpecificNode = node15 && avlTmm.getLeftMost(node => node, node15); expect(getMinNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15); expect(subTreeSum).toBe(70); let lesserSum = 0; avlTmm.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. expect(avlTmm.get(15)).toEqual([15]); const dfs = avlTmm.dfs(node => node, 'IN'); expect(dfs[0].key).toBe(1); expect(dfs[dfs.length - 1].key).toBe(16); avlTmm.perfectlyBalance(); const bfs = avlTmm.bfs(node => node); expect(avlTmm.isPerfectlyBalanced()).toBe(true); expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); expect(avlTmm.delete(avlTmm.getNode(11))[0].deleted?.key).toBe(11); expect(avlTmm.isAVLBalanced()).toBe(true); expect(node15 && avlTmm.getHeight(node15)).toBe(2); expect(avlTmm.delete(1)[0].deleted?.key).toBe(1); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(4); expect(avlTmm.delete(4)[0].deleted?.key).toBe(4); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(4); expect(avlTmm.delete(10)[0].deleted?.key).toBe(10); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(15)[0].deleted?.key).toBe(15); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(5)[0].deleted?.key).toBe(5); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(13)[0].deleted?.key).toBe(13); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(3)[0].deleted?.key).toBe(3); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(8)[0].deleted?.key).toBe(8); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(6)[0].deleted?.key).toBe(6); expect(avlTmm.delete(6).length).toBe(0); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(2); expect(avlTmm.delete(7)[0].deleted?.key).toBe(7); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(2); expect(avlTmm.delete(9)[0].deleted?.key).toBe(9); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(2); expect(avlTmm.delete(14)[0].deleted?.key).toBe(14); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(1); expect(avlTmm.isAVLBalanced()).toBe(true); const lastBFSIds = avlTmm.bfs(); expect(lastBFSIds[0]).toBe(12); expect(lastBFSIds[1]).toBe(2); expect(lastBFSIds[2]).toBe(16); const lastBFSNodes = avlTmm.bfs(node => node); expect(lastBFSNodes[0].key).toBe(12); expect(lastBFSNodes[1].key).toBe(2); expect(lastBFSNodes[2].key).toBe(16); }); it('should add value', () => { const avlTmm = new AVLTreeMultiMap<number, string>([4, 5, [1, ['1']], 2, 3]); expect(avlTmm.get(1)).toEqual(['1']); expect(avlTmm.getNode(1)?.value).toEqual([]); avlTmm.add(1, 'a'); expect(avlTmm.get(1)).toEqual(['1', 'a']); avlTmm.add([1, ['b']]); expect(avlTmm.getNode(1)?.value).toEqual([]); expect(avlTmm.get(1)).toEqual(['1', 'a', 'b']); const treeMap = new AVLTreeMultiMap<number>([4, 5, [1, ['1']], 2, 3]); expect(treeMap.get(1)).toEqual(['1']); expect(treeMap.getNode(1)?.value).toEqual([]); treeMap.add(1, 'a'); expect(treeMap.get(1)).toEqual(['1', 'a']); treeMap.add([1, ['b']]); expect(treeMap.getNode(1)?.value).toEqual([]); expect(treeMap.get(1)).toEqual(['1', 'a', 'b']); }); }); describe('AVLTreeMultiMap Test recursively', () => { it('should perform various operations on a AVLTreeMultiMap', () => { const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; const avlTmm = new AVLTreeMultiMap<number>([], { iterationType: 'RECURSIVE' }); for (const i of arr) avlTmm.add([i, [i]]); const node6 = avlTmm.getNode(6); expect(node6 && avlTmm.getHeight(node6)).toBe(3); expect(node6 && avlTmm.getDepth(node6)).toBe(1); const getNodeById = avlTmm.getNode(10); expect(getNodeById?.key).toBe(10); const getMinNodeByRoot = avlTmm.getLeftMost(); expect(getMinNodeByRoot).toBe(1); const node15 = avlTmm.getNode(15); const getMinNodeBySpecificNode = node15 && avlTmm.getLeftMost(node => node, node15); expect(getMinNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15); expect(subTreeSum).toBe(70); let lesserSum = 0; avlTmm.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. expect(avlTmm.get(15)).toEqual([15]); const dfs = avlTmm.dfs(node => node, 'IN'); expect(dfs[0].key).toBe(1); expect(dfs[dfs.length - 1].key).toBe(16); avlTmm.perfectlyBalance(); const bfs = avlTmm.bfs(node => node); expect(avlTmm.isPerfectlyBalanced()).toBe(true); expect(bfs[0].key).toBe(8); expect(bfs[bfs.length - 1].key).toBe(16); expect(avlTmm.delete(11)[0].deleted?.key).toBe(11); expect(avlTmm.isAVLBalanced()).toBe(true); expect(node15 && avlTmm.getHeight(node15)).toBe(2); expect(avlTmm.delete(1)[0].deleted?.key).toBe(1); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(4); expect(avlTmm.delete(4)[0].deleted?.key).toBe(4); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(4); expect(avlTmm.delete(10)[0].deleted?.key).toBe(10); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(15)[0].deleted?.key).toBe(15); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(5)[0].deleted?.key).toBe(5); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(13)[0].deleted?.key).toBe(13); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(3)[0].deleted?.key).toBe(3); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(8)[0].deleted?.key).toBe(8); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(3); expect(avlTmm.delete(6)[0].deleted?.key).toBe(6); expect(avlTmm.delete(6).length).toBe(0); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(2); expect(avlTmm.delete(7)[0].deleted?.key).toBe(7); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(2); expect(avlTmm.delete(9)[0].deleted?.key).toBe(9); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(2); expect(avlTmm.delete(14)[0].deleted?.key).toBe(14); expect(avlTmm.isAVLBalanced()).toBe(true); expect(avlTmm.getHeight()).toBe(1); expect(avlTmm.isAVLBalanced()).toBe(true); const lastBFSIds = avlTmm.bfs(); expect(lastBFSIds[0]).toBe(12); expect(lastBFSIds[1]).toBe(2); expect(lastBFSIds[2]).toBe(16); const lastBFSNodes = avlTmm.bfs(node => node); expect(lastBFSNodes[0].key).toBe(12); expect(lastBFSNodes[1].key).toBe(2); expect(lastBFSNodes[2].key).toBe(16); }); }); describe('AVLTreeMultiMap APIs test', () => { const avlTmm = new AVLTreeMultiMap<number, { id: number; text: string }>(); beforeEach(() => { avlTmm.clear(); }); it('add', () => { avlTmm.add(1); const node2 = new AVLTreeMultiMapNode(2, []); avlTmm.add(node2); const node3 = new AVLTreeMultiMapNode(3, [ { id: 3, text: 'text3' } ]); avlTmm.add(node3); avlTmm.add([3, [{ id: 3, text: 'text33' }]]); const bfsRes = avlTmm.bfs(node => node.key); expect(bfsRes[0]).toBe(2); }); it('should the clone method', () => { function checkTreeStructure(avlTmm: AVLTreeMultiMap<string, number>) { expect(avlTmm.size).toBe(4); expect(avlTmm.root?.key).toBe('2'); expect(avlTmm.root?.left?.key).toBe('1'); expect(avlTmm.root?.left?.left?.key).toBe(undefined); expect(avlTmm.root?.left?.right?.key).toBe(undefined); expect(avlTmm.root?.right?.key).toBe('4'); expect(avlTmm.root?.right?.left?.key).toBe(undefined); expect(avlTmm.root?.right?.right?.key).toBe('5'); } const avlTmm = new AVLTreeMultiMap<string, number>(); avlTmm.addMany([ ['2', 2], ['4', 4], ['5', 5], ['3', 3], ['1', 1] ]); expect(avlTmm.size).toBe(5); expect(avlTmm.root?.key).toBe('2'); expect(avlTmm.root?.left?.key).toBe('1'); expect(avlTmm.root?.left?.left?.key).toBe(undefined); expect(avlTmm.root?.left?.right?.key).toBe(undefined); expect(avlTmm.root?.right?.key).toBe('4'); expect(avlTmm.root?.right?.left?.key).toBe('3'); expect(avlTmm.root?.right?.right?.key).toBe('5'); avlTmm.delete('3'); checkTreeStructure(avlTmm); const cloned = avlTmm.clone(); checkTreeStructure(cloned); cloned.delete('1'); expect(avlTmm.size).toBe(4); expect(cloned.size).toBe(3); }); }); describe('AVLTreeMultiMap', () => { it('should balance the avlTmm using _balanceLR when nodes are added', () => { const avlTmm = new AVLTreeMultiMap(); avlTmm.add([10, 'A']); avlTmm.add([5, 'B']); avlTmm.add([15, 'C']); avlTmm.add([3, 'D']); avlTmm.add([7, 'E']); // Adding nodes to trigger _balanceLR avlTmm.add([12, 'F']); // You can add more specific assertions to check the avlTmm's balance and structure. }); it('should addMany undefined and null', () => { const avlTmm = new AVLTreeMultiMap<number, string>(); const addManyWithUndefined = avlTmm.addMany([1, undefined, 3]); expect(addManyWithUndefined).toEqual([true, false, true]); expect(avlTmm.get(undefined)).toBe(undefined); const addManyWithNull = avlTmm.addMany([1, null, 3, 4]); expect(addManyWithNull).toEqual([true, false, true, true]); const addManyEntriesWithNull = avlTmm.addMany([ [1, '1'], [null, 'null'], [3, '3'], [4, '4'] ]); expect(addManyEntriesWithNull).toEqual([true, false, true, true]); expect(avlTmm.get(null)).toBe(undefined); const node0 = avlTmm.add(0, '0'); expect(node0).toBe(true); expect(avlTmm.get(0)).toEqual(['0']); }); it('should balance the avlTmm using _balanceLR when nodes are deleted', () => { const avlTmm = new AVLTreeMultiMap(); avlTmm.add([10, 'A']); avlTmm.add([5, 'B']); avlTmm.add([15, 'C']); avlTmm.add([3, 'D']); avlTmm.add([7, 'E']); avlTmm.add([12, 'F']); // Deleting nodes to trigger _balanceLR avlTmm.delete(3); // You can add more specific assertions to check the avlTmm's balance and structure. }); describe('BinaryTree APIs test', () => { const avlTmm = new AVLTreeMultiMap<number, { id: number; text: string }>(); beforeEach(() => { avlTmm.clear(); }); it('add', () => { avlTmm.add(1); const node2 = new AVLTreeMultiMapNode(2, []); avlTmm.add(node2); const node3 = new AVLTreeMultiMapNode(3, [ { id: 3, text: 'text3' } ]); avlTmm.add(node3); avlTmm.add([3, [{ id: 3, text: 'text33' }]]); const bfsRes = avlTmm.bfs(node => node); expect(bfsRes[0]?.key).toBe(2); }); }); }); describe('AVLTreeMultiMap iterative methods test', () => { let avlTmm: AVLTreeMultiMap<number, string, object, string, string, object>; beforeEach(() => { avlTmm = new AVLTreeMultiMap(); avlTmm.add([1, ['a']]); avlTmm.add([2, ['b']]); avlTmm.add([3, ['c']]); }); it('The node obtained by get Node should match the node type', () => { const node3 = avlTmm.getNode(3); expect(node3).toBeInstanceOf(AVLTreeMultiMapNode); }); it('forEach should iterate over all elements', () => { const mockCallback = jest.fn(); avlTmm.forEach((key, value) => { mockCallback(key, value); }); expect(mockCallback.mock.calls.length).toBe(3); expect(mockCallback.mock.calls[0]).toEqual([1, ['a']]); expect(mockCallback.mock.calls[1]).toEqual([2, ['b']]); expect(mockCallback.mock.calls[2]).toEqual([3, ['c']]); }); it('filter should return a new avlTmm with filtered elements', () => { const filteredTree = avlTmm.filter(key => key > 1); expect(filteredTree.size).toBe(2); expect([...filteredTree]).toEqual([ [2, ['b']], [3, ['c']] ]); }); it('map should return a new avlTmm with modified elements', () => { const avlTmmMapped = avlTmm.map((key, value) => [(key * 2).toString(), value ? value : []]); expect(avlTmmMapped.size).toBe(3); expect([...avlTmmMapped]).toEqual([ ['2', ['a']], ['4', ['b']], ['6', ['c']] ]); }); it('reduce should accumulate values', () => { const sum = avlTmm.reduce((acc, value, key) => acc + key, 0); expect(sum).toBe(6); }); it('[Symbol.iterator] should provide an iterator', () => { const entries = []; for (const entry of avlTmm) { entries.push(entry); } expect(entries.length).toBe(3); expect(entries).toEqual([ [1, ['a']], [2, ['b']], [3, ['c']] ]); }); it('should clone work well', () => { const cloned = avlTmm.clone(); expect(cloned.root?.left?.key).toBe(1); expect(cloned.root?.right?.value).toEqual([]); }); it('should keys', () => { const keys = avlTmm.keys(); expect([...keys]).toEqual([1, 2, 3]); }); it('should values', () => { const values = avlTmm.values(); expect([...values]).toEqual([['a'], ['b'], ['c']]); }); it('should leaves', () => { const leaves = avlTmm.leaves(); expect(leaves).toEqual([1, 3]); }); }); describe('AVLTreeMultiMap not map mode', () => { it('should perform various operations on a AVLTreeMultiMap', () => { const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; const avlTmm = new AVLTreeMultiMap<number>([]); for (const i of arr) avlTmm.add([i, [i]]); avlTmm.add(null); const node6 = avlTmm.getNode(6); expect(node6 && avlTmm.getHeight(node6)).toBe(3); expect(node6 && avlTmm.getDepth(node6)).toBe(1); const getNodeById = avlTmm.getNode(10); expect(getNodeById?.key).toBe(10); const getMinNodeByRoot = avlTmm.getLeftMost(); expect(getMinNodeByRoot).toBe(1); const node15 = avlTmm.getNode(15); const getMinNodeBySpecificNode = node15 && avlTmm.getLeftMost(node => node, node15); expect(getMinNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15); expect(subTreeSum).toBe(70); let lesserSum = 0; avlTmm.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. expect(avlTmm.get(node15)).toEqual([15]); }); }); describe('AVLTreeMultiMap not map mode test recursively', () => { it('should perform various operations on a AVLTreeMultiMap', () => { const arr = [11, 3, 15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5]; const avlTmm = new AVLTreeMultiMap<number>([], { iterationType: 'RECURSIVE' }); for (const i of arr) avlTmm.add([i, [i]]); const node6 = avlTmm.getNode(6); expect(node6 && avlTmm.getHeight(node6)).toBe(3); expect(node6 && avlTmm.getDepth(node6)).toBe(1); const getNodeById = avlTmm.getNode(10); expect(getNodeById?.key).toBe(10); const getMinNodeByRoot = avlTmm.getLeftMost(); expect(getMinNodeByRoot).toBe(1); const node15 = avlTmm.getNode(15); const getMinNodeBySpecificNode = node15 && avlTmm.getLeftMost(node => node, node15); expect(getMinNodeBySpecificNode?.key).toBe(12); let subTreeSum = 0; if (node15) avlTmm.dfs(node => (subTreeSum += node.key), 'PRE', false, node15); expect(subTreeSum).toBe(70); let lesserSum = 0; avlTmm.lesserOrGreaterTraverse(node => (lesserSum += node.key), -1, 10); expect(lesserSum).toBe(45); // node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class. expect(avlTmm.get(node15)).toEqual([15]); }); }); describe('AVLTreeMultiMap iterative methods not map mode', () => { let avlTmm: AVLTreeMultiMap<number, string>; beforeEach(() => { avlTmm = new AVLTreeMultiMap<number, string>([]); avlTmm.add([1, ['a']]); avlTmm.add([2, ['b']]); avlTmm.add([3, ['c']]); }); it('should clone work well', () => { const cloned = avlTmm.clone(); expect(cloned.root?.left?.key).toBe(1); expect(cloned.get(cloned.root?.right?.key)).toEqual(['c']); }); }); describe('classic use', () => { // Test suite for TreeMultiMap with player ranking and equipment it('players ranked by score with their equipment', () => { type Equipment = { name: string; // Equipment name quality: 'legendary' | 'epic' | 'rare' | 'common'; level: number; }; type Player = { name: string; score: number; equipments: Equipment[]; }; // Mock player data with their scores and equipment const players: Player[] = [ { name: 'DragonSlayer', score: 8750, equipments: [ { name: 'AWM', quality: 'legendary', level: 85 }, { name: 'Level 3 Helmet', quality: 'epic', level: 80 }, { name: 'Extended Quickdraw Mag', quality: 'rare', level: 75 }, { name: 'Compensator', quality: 'epic', level: 78 }, { name: 'Vertical Grip', quality: 'rare', level: 72 } ] }, { name: 'ShadowNinja', score: 7200, equipments: [ { name: 'M416', quality: 'epic', level: 75 }, { name: 'Ghillie Suit', quality: 'rare', level: 70 }, { name: 'Red Dot Sight', quality: 'common', level: 65 }, { name: 'Extended QuickDraw Mag', quality: 'rare', level: 68 } ] }, { name: 'RuneMaster', score: 9100, equipments: [ { name: 'KAR98K', quality: 'legendary', level: 90 }, { name: 'Level 3 Vest', quality: 'legendary', level: 85 }, { name: 'Holographic Sight', quality: 'epic', level: 82 }, { name: 'Suppressor', quality: 'legendary', level: 88 }, { name: 'Level 3 Backpack', quality: 'epic', level: 80 } ] }, { name: 'BattleKing', score: 8500, equipments: [ { name: 'AUG', quality: 'epic', level: 82 }, { name: 'Red Dot Sight', quality: 'rare', level: 75 }, { name: 'Extended Mag', quality: 'common', level: 70 }, { name: 'Tactical Stock', quality: 'rare', level: 76 } ] }, { name: 'SniperElite', score: 7800, equipments: [ { name: 'M24', quality: 'legendary', level: 88 }, { name: 'Compensator', quality: 'epic', level: 80 }, { name: 'Scope 8x', quality: 'legendary', level: 85 }, { name: 'Level 2 Helmet', quality: 'rare', level: 75 } ] }, { name: 'RushMaster', score: 7500, equipments: [ { name: 'Vector', quality: 'rare', level: 72 }, { name: 'Level 2 Helmet', quality: 'common', level: 65 }, { name: 'Quickdraw Mag', quality: 'common', level: 60 }, { name: 'Laser Sight', quality: 'rare', level: 68 } ] }, { name: 'GhostWarrior', score: 8200, equipments: [ { name: 'SCAR-L', quality: 'epic', level: 78 }, { name: 'Extended Quickdraw Mag', quality: 'rare', level: 70 }, { name: 'Holographic Sight', quality: 'epic', level: 75 }, { name: 'Suppressor', quality: 'rare', level: 72 }, { name: 'Vertical Grip', quality: 'common', level: 65 } ] }, { name: 'DeathDealer', score: 7300, equipments: [ { name: 'SKS', quality: 'epic', level: 76 }, { name: 'Holographic Sight', quality: 'rare', level: 68 }, { name: 'Extended Mag', quality: 'common', level: 65 } ] }, { name: 'StormRider', score: 8900, equipments: [ { name: 'MK14', quality: 'legendary', level: 92 }, { name: 'Level 3 Backpack', quality: 'legendary', level: 85 }, { name: 'Scope 8x', quality: 'epic', level: 80 }, { name: 'Suppressor', quality: 'legendary', level: 88 }, { name: 'Tactical Stock', quality: 'rare', level: 75 } ] }, { name: 'CombatLegend', score: 7600, equipments: [ { name: 'UMP45', quality: 'rare', level: 74 }, { name: 'Level 2 Vest', quality: 'common', level: 67 }, { name: 'Red Dot Sight', quality: 'common', level: 62 }, { name: 'Extended Mag', quality: 'rare', level: 70 } ] } ]; // Create a TreeMultiMap for player rankings const playerRankings = new AVLTreeMultiMap<number, Equipment, Player>(players, { toEntryFn: ({ score, equipments }) => [score, equipments], isMapMode: false }); const topPlayersEquipments = playerRankings.rangeSearch([8900, 10000], node => playerRankings.get(node)); expect(topPlayersEquipments).toEqual([ [ { name: 'MK14', quality: 'legendary', level: 92 }, { name: 'Level 3 Backpack', quality: 'legendary', level: 85 }, { name: 'Scope 8x', quality: 'epic', level: 80 }, { name: 'Suppressor', quality: 'legendary', level: 88 }, { name: 'Tactical Stock', quality: 'rare', level: 75 } ], [ { name: 'KAR98K', quality: 'legendary', level: 90 }, { name: 'Level 3 Vest', quality: 'legendary', level: 85 }, { name: 'Holographic Sight', quality: 'epic', level: 82 }, { name: 'Suppressor', quality: 'legendary', level: 88 }, { name: 'Level 3 Backpack', quality: 'epic', level: 80 } ] ]); }); });