UNPKG

@gamepark/rules-api

Version:

API to implement the rules of a board game

175 lines 8.67 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Money = void 0; var forEachRight_1 = __importDefault(require("lodash/forEachRight")); var isEqual_1 = __importDefault(require("lodash/isEqual")); var keyBy_1 = __importDefault(require("lodash/keyBy")); var mapValues_1 = __importDefault(require("lodash/mapValues")); var sumBy_1 = __importDefault(require("lodash/sumBy")); /** * This class help manipulate any kind of money with arbitrary unit values, like a set of coins of values 1, 2, 5, 10 for instance. * @deprecated use {@link MaterialMoney} instead */ var Money = /** @class */ (function () { function Money(units) { this.units = units; this.units.sort(function (a, b) { return a - b; }); } /** * Count the total value of a material instance * @param material The material to count * @returns the sum of each item id multiplied by its quantity */ Money.prototype.count = function (material) { return (0, sumBy_1.default)(material.getItems(), function (item) { var _a, _b; return ((_a = item.id) !== null && _a !== void 0 ? _a : 1) * ((_b = item.quantity) !== null && _b !== void 0 ? _b : 1); }); }; /** * Perform an operation of adding or removing an amount from a location by creating or deleting items * @param material The material instance * @param location The location to filter material onto, and to create new items in * @param amount Amount to create or delete * @returns the moves that need to be played to perform the operation */ Money.prototype.createOrDelete = function (material, location, amount) { material = material.location(function (l) { return (0, isEqual_1.default)(l, location); }); var moves = []; var delta = amount > 0 ? this.gain(amount) : this.spend((0, mapValues_1.default)((0, keyBy_1.default)(this.units), function (unit) { return material.id(unit).getQuantity(); }), -amount); for (var index = this.units.length - 1; index >= 0; index--) { var unit = this.units[index]; if (delta[unit] < 0) { moves.push(material.id(unit).deleteItem(-delta[unit])); } else if (delta[unit] > 0) { moves.push(material.createItem({ id: unit, location: location, quantity: delta[unit] })); } } return moves; }; /** * Move an amount of money from a place to another place. It searches after the easiest way to do it, making money with the bank only if necessary. * @param material Material instance for the money (needs to be unfiltered) * @param origin Location to remove money from * @param target Location to move money to * @param amount Amount of money to transfer * @returns the moves that need to be played to perform the operation */ Money.prototype.moveAmount = function (material, origin, target, amount) { if (!amount) return []; if (amount < 0) return this.moveAmount(material, target, origin, -amount); var moves = []; var originMaterial = material.location(function (l) { return (0, isEqual_1.default)(l, origin); }); var targetMaterial = material.location(function (l) { return (0, isEqual_1.default)(l, target); }); var originUnits = (0, mapValues_1.default)((0, keyBy_1.default)(this.units), function (unit) { return originMaterial.id(unit).getQuantity(); }); var originDelta = this.spend(originUnits, amount); var targetDelta = this.gain(amount); for (var index = this.units.length - 1; index >= 0; index--) { var unit = this.units[index]; if (originDelta[unit] < 0) { var _loop_1 = function () { var lowerUnits = this_1.units.slice(0, this_1.units.indexOf(unit)); var targetResult = (0, mapValues_1.default)((0, keyBy_1.default)(lowerUnits), function (unit) { return targetMaterial.id(unit).getQuantity() + targetDelta[unit]; }); var targetResultDelta = this_1.spend(targetResult, unit); var valueSpent = (0, sumBy_1.default)(lowerUnits, function (unit) { return -targetResultDelta[unit] * unit; }); if (valueSpent === unit && lowerUnits.every(function (lowerUnit) { return targetResultDelta[lowerUnit] < 0; })) { targetDelta[unit]++; for (var _i = 0, lowerUnits_1 = lowerUnits; _i < lowerUnits_1.length; _i++) { var lowerUnit = lowerUnits_1[_i]; targetDelta[lowerUnit] += targetResultDelta[lowerUnit]; } } else return "break"; }; var this_1 = this; while (targetDelta[unit] < -originDelta[unit]) { var state_1 = _loop_1(); if (state_1 === "break") break; } var moveAmount = Math.min(-originDelta[unit], targetDelta[unit]); targetDelta[unit] -= moveAmount; var originMaterialUnit = originMaterial.id(unit); if (moveAmount > 0) { moves.push(originMaterialUnit.moveItem(target, moveAmount)); } if (moveAmount < -originDelta[unit]) { moves.push(originMaterialUnit.deleteItem(-originDelta[unit] - moveAmount)); } } else if (originDelta[unit] > 0) { if (targetDelta[unit] < 0) { moves.push(targetMaterial.id(unit).moveItem(origin, -targetDelta[unit])); } else { moves.push(material.createItem({ id: unit, location: origin, quantity: originDelta[unit] })); } } if (targetDelta[unit] > 0) { moves.push(material.createItem({ id: unit, location: target, quantity: targetDelta[unit] })); } } return moves; }; Object.defineProperty(Money.prototype, "record", { /** * Creates a new record indexes by all units, with value equal to 0 for each unit */ get: function () { return (0, mapValues_1.default)((0, keyBy_1.default)(this.units), function (_) { return 0; }); }, enumerable: false, configurable: true }); /** * Return the best way to gain an amount, prioritizing the highest unit values * @param amount Amount to gain, default 1 * @returns the record of coins to earn (only positive values) */ Money.prototype.gain = function (amount) { if (amount === void 0) { amount = 1; } var gain = this.record; (0, forEachRight_1.default)(this.units, function (unit) { gain[unit] = Math.floor(amount / unit); amount %= unit; }); return gain; }; /** * Return the best way to spend an amount of owned units, prioritizing the smallest unit values * @param owned Amount of units owned before spending * @param amount Amount to gain, default 1 * @returns the record of coins to give away and eventually take (positive and negative values) */ Money.prototype.spend = function (owned, amount) { if (amount === void 0) { amount = 1; } var delta = (0, mapValues_1.default)(owned, function (_) { return 0; }); for (var _1 = 0; _1 < amount; _1++) { for (var _i = 0, _a = this.units; _i < _a.length; _i++) { var unit = _a[_i]; if (owned[unit] + delta[unit] > 0) { delta[unit]--; if (unit > 1) { var rest = unit - 1; for (var _b = 0, _c = this.units.slice(0, this.units.indexOf(unit)).reverse(); _b < _c.length; _b++) { var lowerUnit = _c[_b]; if (lowerUnit <= rest) { delta[lowerUnit] += Math.floor(rest / lowerUnit); rest -= rest % lowerUnit; } } } break; } } } return delta; }; return Money; }()); exports.Money = Money; //# sourceMappingURL=money.util.js.map