mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-20 05:05:47 +01:00
CCT: Minor simplification of 'Shortest Path' solver (#1288)
BFS shouldn't need some checks. Also allows deletion of a helper file used by this function only.
This commit is contained in:
parent
08eb60d21b
commit
fe14d4fef3
@ -1,5 +1,4 @@
|
|||||||
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
|
import { getRandomIntInclusive } from "../utils/helpers/getRandomIntInclusive";
|
||||||
import { MinHeap } from "../utils/Heap";
|
|
||||||
|
|
||||||
import { comprGenChar, comprLZGenerate, comprLZEncode, comprLZDecode } from "../utils/CompressionContracts";
|
import { comprGenChar, comprLZGenerate, comprLZEncode, comprLZDecode } from "../utils/CompressionContracts";
|
||||||
import { HammingEncode, HammingDecode, HammingEncodeProperly } from "../utils/HammingCodeTools";
|
import { HammingEncode, HammingDecode, HammingEncodeProperly } from "../utils/HammingCodeTools";
|
||||||
@ -994,7 +993,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
|
|
||||||
const distance: [number][] = new Array(height);
|
const distance: [number][] = new Array(height);
|
||||||
//const prev: [[number, number] | undefined][] = new Array(height);
|
//const prev: [[number, number] | undefined][] = new Array(height);
|
||||||
const queue = new MinHeap<[number, number]>();
|
const queue: [number, number][] = [];
|
||||||
|
|
||||||
for (let y = 0; y < height; y++) {
|
for (let y = 0; y < height; y++) {
|
||||||
distance[y] = new Array(width).fill(Infinity) as [number];
|
distance[y] = new Array(width).fill(Infinity) as [number];
|
||||||
@ -1015,21 +1014,15 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
|
|
||||||
// Prepare starting point
|
// Prepare starting point
|
||||||
distance[0][0] = 0;
|
distance[0][0] = 0;
|
||||||
queue.push([0, 0], 0);
|
queue.push([0, 0]);
|
||||||
|
|
||||||
// Take next-nearest position and expand potential paths from there
|
// Take next-nearest position and expand potential paths from there
|
||||||
while (queue.size > 0) {
|
while (queue.length > 0) {
|
||||||
const [y, x] = queue.pop() as [number, number];
|
const [y, x] = queue.shift() as [number, number];
|
||||||
for (const [yN, xN] of neighbors(y, x)) {
|
for (const [yN, xN] of neighbors(y, x)) {
|
||||||
const d = distance[y][x] + 1;
|
if (distance[yN][xN] == Infinity) {
|
||||||
if (d < distance[yN][xN]) {
|
queue.push([yN, xN]);
|
||||||
if (distance[yN][xN] == Infinity)
|
distance[yN][xN] = distance[y][x] + 1;
|
||||||
// Not reached previously
|
|
||||||
queue.push([yN, xN], d);
|
|
||||||
// Found a shorter path
|
|
||||||
else queue.changeWeight(([yQ, xQ]) => yQ == yN && xQ == xN, d);
|
|
||||||
//prev[yN][xN] = [y, x];
|
|
||||||
distance[yN][xN] = d;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
/** Binary heap. */
|
|
||||||
abstract class BinHeap<T> {
|
|
||||||
/**
|
|
||||||
* Heap data array consisting of [weight, payload] pairs, arranged by weight
|
|
||||||
* to satisfy heap condition.
|
|
||||||
*
|
|
||||||
* Encodes the binary tree by storing tree root at index 0 and
|
|
||||||
* left child of element i at `i * 2 + 1` and
|
|
||||||
* right child of element i at `i * 2 + 2`.
|
|
||||||
*/
|
|
||||||
protected data: [number, T][];
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.data = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get number of elements in the heap. */
|
|
||||||
public get size(): number {
|
|
||||||
return this.data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 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);
|
|
||||||
// Try shifting deeper
|
|
||||||
else this.heapifyDown(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Restore heap condition, starting at index i and traveling towards root. */
|
|
||||||
protected heapifyUp(i: number): void {
|
|
||||||
// Swap the new element up towards root until it reaches root position or
|
|
||||||
// settles under under a suitable parent
|
|
||||||
while (i > 0) {
|
|
||||||
const p = Math.floor((i - 1) / 2);
|
|
||||||
|
|
||||||
// Reached heap-ordered state already?
|
|
||||||
if (this.heapOrderABeforeB(this.data[p][0], this.data[i][0])) break;
|
|
||||||
|
|
||||||
// Swap
|
|
||||||
const tmp = this.data[p];
|
|
||||||
this.data[p] = this.data[i];
|
|
||||||
this.data[i] = tmp;
|
|
||||||
|
|
||||||
// And repeat at parent index
|
|
||||||
i = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Restore heap condition, starting at index i and traveling away from root. */
|
|
||||||
protected heapifyDown(i: number): void {
|
|
||||||
// Swap the shifted element down in the heap until it either reaches the
|
|
||||||
// bottom layer or is in correct order relative to it's children
|
|
||||||
while (i < this.data.length) {
|
|
||||||
const l = i * 2 + 1;
|
|
||||||
const r = i * 2 + 2;
|
|
||||||
let toSwap = i;
|
|
||||||
|
|
||||||
// Find which one of element i and it's children should be closest to root
|
|
||||||
if (l < this.data.length && this.heapOrderABeforeB(this.data[l][0], this.data[toSwap][0])) toSwap = l;
|
|
||||||
if (r < this.data.length && this.heapOrderABeforeB(this.data[r][0], this.data[toSwap][0])) toSwap = r;
|
|
||||||
|
|
||||||
// Already in order?
|
|
||||||
if (i == toSwap) break;
|
|
||||||
|
|
||||||
// Not in order. Swap child that should be closest to root up to 'i' and repeat
|
|
||||||
const tmp = this.data[toSwap];
|
|
||||||
this.data[toSwap] = this.data[i];
|
|
||||||
this.data[i] = tmp;
|
|
||||||
|
|
||||||
i = toSwap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should element with weight `weightA` be closer to root than element with
|
|
||||||
* weight `weightB`?
|
|
||||||
*/
|
|
||||||
protected abstract heapOrderABeforeB(weightA: number, weightB: number): boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Binary max-heap. */
|
|
||||||
export class MaxHeap<T> extends BinHeap<T> {
|
|
||||||
heapOrderABeforeB(weightA: number, weightB: number): boolean {
|
|
||||||
return weightA > weightB;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Binary min-heap. */
|
|
||||||
export class MinHeap<T> extends BinHeap<T> {
|
|
||||||
heapOrderABeforeB(weightA: number, weightB: number): boolean {
|
|
||||||
return weightA < weightB;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user