UNPKG

@theatrejs/theatrejs

Version:

🎮 A JavaScript 2D Game Engine focused on creating pixel art games.

186 lines (140 loc) • 3.52 kB
/** * Creates heaps. * @template {any} TypeGeneric The generic type of the items. * * @example * * // without chaining * const heap = new Heap(compare); * heap.push(four); * heap.push(one); * heap.push(two); * * const maximum = heap.pop(); * * @example * * // with chaining * const heap = new Heap(compare).push(four).push(one).push(two); * * const maximum = heap.pop(); */ class Heap { /** * @template {any} TypeGeneric The generic type of the items. * @callback TypeHandlerCompare A handler to use to compare the two given items. * @param {TypeGeneric} $a The first item to compare. * @param {TypeGeneric} $b The second item to compare. * @returns {number} * @protected * * @memberof Heap */ /** * Stores the compare handler. * @type {TypeHandlerCompare<TypeGeneric>} * @private */ $compare; /** * Stores the items. * @type {Array<TypeGeneric>} * @private */ $items; /** * Gets the size of the heap. * @type {number} * @public */ get size() { return this.$items.length; } /** * Creates a new heap. * @param {TypeHandlerCompare<TypeGeneric>} $compare The compare handler. */ constructor($compare) { this.$compare = $compare; this.$items = []; } /** * Shifts down an item from its given index. * @param {number} [$index] The index of the item to shift down. * @private */ $shiftDown($index = 0) { const left = ($index * 2) + 1; const right = ($index * 2) + 2; let best = $index; if (left < this.$items.length && this.$compare(this.$items[best], this.$items[left]) > 0) { best = left; } if (right < this.$items.length && this.$compare(this.$items[best], this.$items[right]) > 0) { best = right; } if (best === $index) { return; } this.$swap($index, best); this.$shiftDown(best); } /** * Shifts up the last item. * @private */ $shiftUp() { let index = this.$items.length - 1; while (index > 0) { const parent = Math.floor((index - 1) / 2); if (this.$compare(this.$items[index], this.$items[parent]) >= 0) { break; } this.$swap(index, parent); index = parent; } } /** * Swaps items at the two given indices. * @param {number} $a The index of the first item to swap. * @param {number} $b The index of the second item to swap. * @private */ $swap($a, $b) { [this.$items[$a], this.$items[$b]] = [this.$items[$b], this.$items[$a]]; } /** * Pops an item. * @returns {(TypeGeneric | undefined)} * @public */ pop() { if (this.$items.length === 0) { return undefined; } if (this.$items.length === 1) { return this.$items.pop(); } this.$swap(0, this.$items.length - 1); const best = this.$items.pop(); this.$shiftDown(); return best; } /** * Pushes an item. * @param {TypeGeneric} $item The item to push. * @returns {this} * @public */ push($item) { this.$items.push($item); this.$shiftUp(); return this; } } export { Heap }; export default Heap;