diff --git a/src/data/codingcontracttypes.ts b/src/data/codingcontracttypes.ts index 3265302cb..cf53a8938 100644 --- a/src/data/codingcontracttypes.ts +++ b/src/data/codingcontracttypes.ts @@ -864,12 +864,12 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [ //prev[y] = new Array(width).fill(undefined) as [undefined]; } - function validPosition(y: number, x: number) { + function validPosition(y: number, x: number): boolean { return y >= 0 && y < height && x >= 0 && x < width && data[y][x] == 0; } // List in-bounds and passable neighbors - function* neighbors(y: number, x: number) { + function* neighbors(y: number, x: number): Generator<[number, number]> { if(validPosition(y - 1, x)) yield [y - 1, x]; // Up if(validPosition(y + 1, x)) yield [y + 1, x]; // Down if(validPosition(y, x - 1)) yield [y, x - 1]; // Left diff --git a/src/utils/Heap.ts b/src/utils/Heap.ts index 9f508048a..ea31ed7bc 100644 --- a/src/utils/Heap.ts +++ b/src/utils/Heap.ts @@ -15,15 +15,58 @@ abstract class BinHeap { } /** Get number of elements in the heap. */ - public get size() { + public get size(): number { return this.data.length; } - /** - * Should element with weight `weightA` be closer to root than element with - * weight `weightB`? - */ - protected abstract heapOrderABeforeB(weightA: number, weightB: number): boolean; + /** Add a new element to the heap. */ + public push(value: T, weight: number): void { + const i = this.data.length; + this.data[i] = [weight, value]; + this.heapifyUp(i); + } + + /** Get the value of the root-most element of the heap, without changing the heap. */ + public peek(): T | undefined { + if(this.data.length == 0) + return undefined; + + return this.data[0][1]; + } + + /** Remove the root-most element of the heap and return the removed element's value. */ + public pop(): T | undefined { + if(this.data.length == 0) + return undefined; + + const value = this.data[0][1]; + + this.data[0] = this.data[this.data.length - 1]; + this.data.length = this.data.length - 1; + + this.heapifyDown(0); + + return value; + } + + /** Change the weight of an element in the heap. */ + public changeWeight(predicate: (value: T) => boolean, weight: number): void { + // Find first element with matching value, if any + const i = this.data.findIndex(e => predicate(e[1])); + if(i == -1) + return; + + // Update that element's weight + this.data[i][0] = weight; + + // And re-heapify if needed + const p = Math.floor((i - 1) / 2); + + if(!this.heapOrderABeforeB(this.data[p][0], this.data[i][0])) // Needs to shift root-wards? + this.heapifyUp(i); + else // Try shifting deeper + this.heapifyDown(i); + } /** Restore heap condition, starting at index i and traveling towards root. */ protected heapifyUp(i: number): void { @@ -74,56 +117,11 @@ abstract class BinHeap { } } - /** Add a new element to the heap. */ - public push(value: T, weight: number): void { - const i = this.data.length; - this.data[i] = [weight, value]; - this.heapifyUp(i); - } - - /** Get the value of the root-most element of the heap, without changing the heap. */ - public peek(): T | undefined { - if(this.data.length == 0) - return undefined; - - return this.data[0][1]; - } - - /** Remove the root-most element of the heap and return the removed element's value. */ - public pop(): T | undefined { - if(this.data.length == 0) - return undefined; - - const value = this.data[0][1]; - - this.data[0] = this.data[this.data.length - 1]; - this.data.length = this.data.length - 1; - - this.heapifyDown(0); - - return value; - } - - /** Change the weight of an element in the heap. */ - public changeWeight(predicate: (value: T) => boolean, weight: number): void { - // Find first element with matching value, if any - const i = this.data.findIndex(([_, v]) => predicate(v)); - if(i == -1) - return; - - // Update that element's weight - this.data[i][0] = weight; - - // And re-heapify if needed - const p = Math.floor((i - 1) / 2); - const l = i * 2 + 1; - const r = i * 2 + 2; - - if(!this.heapOrderABeforeB(this.data[p][0], this.data[i][0])) // Needs to shift root-wards? - this.heapifyUp(i); - else // Try shifting deeper - this.heapifyDown(i); - } + /** + * Should element with weight `weightA` be closer to root than element with + * weight `weightB`? + */ + protected abstract heapOrderABeforeB(weightA: number, weightB: number): boolean; }