UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

170 lines (133 loc) 3.9 kB
import { assert } from "../../../core/assert.js"; /** * Sorting comparator * @param {ResourceAllocationBid} a * @param {ResourceAllocationBid} b * @returns {number} */ function byWeightedValue(a, b) { const v0 = a.value * a.weight; const v1 = b.value * b.weight; return v1 - v0; } /** * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class ResourceAllocationSolver { /** * * @type {Map<any,Resource>} * @private */ resources = new Map(); /** * * @type {ResourceAllocationBid[]} * @private */ bids = []; /** * * @type {ResourceAllocationBid[]} * @private */ allocations = []; clear() { this.resources.clear(); this.bids = []; this.allocations = []; } /** * * @param {Resource[]} resources */ addResources(resources) { resources.forEach(r => this.addResource(r)); } /** * * @param {Resource} resource */ addResource(resource) { const type = resource.type; const existingResource = this.resources.get(type); if (existingResource === undefined) { this.resources.set(type, resource); } else { existingResource.amount += resource.amount; } } /** * * @param {ResourceAllocationBid[]} bids */ addBids(bids) { bids.forEach(b => this.addBid(b)); } /** * * @param {ResourceAllocationBid} bid */ addBid(bid) { assert.ok(bid.value >= 0 && bid.value <= 1, `expected 0 >= value <= 1, instead got '${bid.value}'`); this.bids.push(bid); } /** * The problem is that of dynamic programming. Often called "knapsack problem" we want to assign resources in the best possible way * TODO: the algorithm is very greedy, there is a lot of room for optimization * @returns {ResourceAllocationBid[]} */ solve() { /** * * @type {Map<any, Resource>} */ const availableResources = new Map(); //populate lookup map this.resources.forEach((r, type) => { const resource = r.clone(); availableResources.set(type, resource); }); //make a copy of bids to preserve original before sorting const bids = this.bids.slice(); //sort bids by value bids.sort(byWeightedValue); /** * * @param {ResourceAllocationBid} bid */ function assignResources(bid) { const allocation = bid.allocation; const bidResources = allocation.resources; //check if resources are there for (const bidResource of bidResources) { const resource = availableResources.get(bidResource.type); if (resource === undefined) { //resource doesn't exist return false; } if (resource.amount < bidResource.amount) { //insufficient resource return false; } } //assign the resources for (const bidResource of bidResources) { const resource = availableResources.get(bidResource.type); resource.amount -= bidResource.amount; } return true; } //assign bids this.allocations = []; bids.forEach(b => { const success = assignResources(b); if (success) { this.allocations.push(b); } }); return this.allocations; } }