Fix non-integrable requirements crashing in cost requirements with spendResources true

(Which should be valid in the event the dev doesn't want to maximize)
This commit is contained in:
thepaperpilot 2023-04-22 17:58:31 -05:00
parent 97fcd28fe2
commit f7f4d0aa9f
2 changed files with 90 additions and 10 deletions

View file

@ -101,6 +101,7 @@ export type CostRequirement = Replace<
visibility: ProcessedComputable<Visibility.Visible | Visibility.None | boolean>; visibility: ProcessedComputable<Visibility.Visible | Visibility.None | boolean>;
requiresPay: ProcessedComputable<boolean>; requiresPay: ProcessedComputable<boolean>;
spendResources: ProcessedComputable<boolean>; spendResources: ProcessedComputable<boolean>;
canMaximize: ProcessedComputable<boolean>;
} }
>; >;
@ -159,14 +160,33 @@ export function createCostRequirement<T extends CostRequirementOptions>(
req.resource.value = Decimal.sub(req.resource.value, cost).max(0); req.resource.value = Decimal.sub(req.resource.value, cost).max(0);
}); });
req.canMaximize = req.cost instanceof Formula && req.cost.isInvertible(); req.canMaximize = computed(
() =>
req.cost instanceof Formula &&
req.cost.isInvertible() &&
(unref(req.spendResources) === false || req.cost.isIntegrable())
);
if (req.canMaximize) { if (req.cost instanceof Formula && req.cost.isInvertible()) {
req.requirementMet = calculateMaxAffordable( const maxAffordable = calculateMaxAffordable(
req.cost as InvertibleFormula, req.cost,
req.resource, req.resource,
unref(req.spendResources) as boolean unref(req.spendResources) as boolean
); );
req.requirementMet = computed(() => {
if (unref(req.canMaximize)) {
return maxAffordable.value;
} else {
if (req.cost instanceof Formula) {
return Decimal.gte(req.resource.value, req.cost.evaluate());
} else {
return Decimal.gte(
req.resource.value,
unref(req.cost as ProcessedComputable<DecimalSource>)
);
}
}
});
} else { } else {
req.requirementMet = computed(() => { req.requirementMet = computed(() => {
if (req.cost instanceof Formula) { if (req.cost instanceof Formula) {

View file

@ -16,11 +16,14 @@ import { isRef, ref, unref } from "vue";
import "../utils"; import "../utils";
describe("Creating cost requirement", () => { describe("Creating cost requirement", () => {
describe("Minimal requirement", () => {
let resource: Resource; let resource: Resource;
let requirement: CostRequirement;
beforeAll(() => { beforeAll(() => {
resource = createResource(ref(10)); resource = createResource(ref(10));
});
describe("Minimal requirement", () => {
let requirement: CostRequirement;
beforeAll(() => {
requirement = createCostRequirement(() => ({ requirement = createCostRequirement(() => ({
resource, resource,
cost: 10, cost: 10,
@ -46,10 +49,8 @@ describe("Creating cost requirement", () => {
}); });
describe("Fully customized", () => { describe("Fully customized", () => {
let resource: Resource;
let requirement: CostRequirement; let requirement: CostRequirement;
beforeAll(() => { beforeAll(() => {
resource = createResource(ref(10));
requirement = createCostRequirement(() => ({ requirement = createCostRequirement(() => ({
resource, resource,
cost: Formula.variable(resource).times(10), cost: Formula.variable(resource).times(10),
@ -73,7 +74,6 @@ describe("Creating cost requirement", () => {
}); });
test("Requirement met when meeting the cost", () => { test("Requirement met when meeting the cost", () => {
const resource = createResource(ref(10));
const requirement = createCostRequirement(() => ({ const requirement = createCostRequirement(() => ({
resource, resource,
cost: 10, cost: 10,
@ -83,7 +83,6 @@ describe("Creating cost requirement", () => {
}); });
test("Requirement not met when not meeting the cost", () => { test("Requirement not met when not meeting the cost", () => {
const resource = createResource(ref(10));
const requirement = createCostRequirement(() => ({ const requirement = createCostRequirement(() => ({
resource, resource,
cost: 100, cost: 100,
@ -91,6 +90,67 @@ describe("Creating cost requirement", () => {
})); }));
expect(unref(requirement.requirementMet)).toBe(false); expect(unref(requirement.requirementMet)).toBe(false);
}); });
describe("canMaximize works correctly", () => {
test("Cost function cannot maximize", () =>
expect(
unref(
createCostRequirement(() => ({
resource,
cost: () => 10
})).canMaximize
)
).toBe(false));
test("Non-invertible formula cannot maximize", () =>
expect(
unref(
createCostRequirement(() => ({
resource,
cost: Formula.variable(resource).abs()
})).canMaximize
)
).toBe(false));
test("Invertible formula can maximize if spendResources is false", () =>
expect(
unref(
createCostRequirement(() => ({
resource,
cost: Formula.variable(resource).lambertw(),
spendResources: false
})).canMaximize
)
).toBe(true));
test("Invertible formula cannot maximize if spendResources is true", () =>
expect(
unref(
createCostRequirement(() => ({
resource,
cost: Formula.variable(resource).lambertw(),
spendResources: true
})).canMaximize
)
).toBe(false));
test("Integrable formula can maximize if spendResources is false", () =>
expect(
unref(
createCostRequirement(() => ({
resource,
cost: Formula.variable(resource).pow(2),
spendResources: false
})).canMaximize
)
).toBe(true));
test("Integrable formula can maximize if spendResources is true", () =>
expect(
unref(
createCostRequirement(() => ({
resource,
cost: Formula.variable(resource).pow(2),
spendResources: true
})).canMaximize
)
).toBe(true));
});
}); });
describe("Creating visibility requirement", () => { describe("Creating visibility requirement", () => {