data-structure-typed
Version:
Standard data structure
741 lines (629 loc) • 25.3 kB
text/typescript
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 }
]
]);
});
});