forked from profectus/Profectus
Compare commits
36 commits
ducdat0507
...
main
Author | SHA1 | Date | |
---|---|---|---|
1b809a9550 | |||
|
cf6265d8ce | ||
4f807aaf96 | |||
ffc42a5745 | |||
|
8811996f64 | ||
|
7750a3368d | ||
2495dc9783 | |||
e66daad7a2 | |||
8065f8efa4 | |||
e9283b5cca | |||
2c615ea524 | |||
953cd8047e | |||
766c600a70 | |||
c1d0b7eec6 | |||
52b500c9d8 | |||
aabb0a1bba | |||
005bf5da9a | |||
7330a6bda4 | |||
65ff440e25 | |||
acf1d24c15 | |||
d16bb55c3c | |||
312cab1347 | |||
6d148da260 | |||
a5204106aa | |||
0cccf7aecc | |||
d0fffd3b89 | |||
3fe0311331 | |||
eee5ac3e2d | |||
9edda4d957 | |||
6ad08c4052 | |||
e0f1296b35 | |||
c8ba77b89b | |||
63dcad4c12 | |||
d6c9f95851 | |||
210c2290f0 | |||
e896fd84cf |
22 changed files with 196 additions and 53 deletions
31
.forgejo/workflows/deploy.yaml
Normal file
31
.forgejo/workflows/deploy.yaml
Normal file
|
@ -0,0 +1,31 @@
|
|||
name: Build and Deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
if: github.repository != 'profectus-engine/Profectus' # Don't build placeholder mod on main repo
|
||||
runs-on: docker
|
||||
steps:
|
||||
- name: Setup RSync
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y rsync
|
||||
|
||||
- name: Checkout 🛎️
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Deploy 🚀
|
||||
uses: https://github.com/JamesIves/github-pages-deploy-action@v4.2.5
|
||||
with:
|
||||
branch: pages # The branch the action should deploy to.
|
||||
folder: dist # The folder the action should deploy.
|
21
.forgejo/workflows/test.yaml
Normal file
21
.forgejo/workflows/test.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
name: Run Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: docker
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Use Node.js 16.x
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16.x
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
1
.github/workflows/deploy.yml
vendored
1
.github/workflows/deploy.yml
vendored
|
@ -3,6 +3,7 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- 'main'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
if: github.repository != 'profectus-engine/Profectus' # Don't build placeholder mod on main repo
|
||||
|
|
4
.github/workflows/test.yml
vendored
4
.github/workflows/test.yml
vendored
|
@ -1,11 +1,11 @@
|
|||
name: Build and Deploy
|
||||
name: Run Tests
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
target="_blank"
|
||||
>
|
||||
<span class="material-icons info-modal-discord">discord</span>
|
||||
The Paper Pilot Community
|
||||
Profectus & Friends
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
class="nan-modal-discord-link"
|
||||
>
|
||||
<span class="material-icons nan-modal-discord">discord</span>
|
||||
{{ discordName || "The Paper Pilot Community" }}
|
||||
{{ discordName || "Profectus & Friends" }}
|
||||
</a>
|
||||
</div>
|
||||
<br />
|
||||
|
|
|
@ -15,9 +15,7 @@
|
|||
<a :href="discordLink" target="_blank">{{ discordName }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discord.gg/yJ4fjnjU54" target="_blank"
|
||||
>The Paper Pilot Community</a
|
||||
>
|
||||
<a href="https://discord.gg/yJ4fjnjU54" target="_blank">Profectus & Friends</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discord.gg/F3xveHV" target="_blank">The Modding Tree</a>
|
||||
|
@ -82,9 +80,7 @@
|
|||
<a :href="discordLink" target="_blank">{{ discordName }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discord.gg/yJ4fjnjU54" target="_blank"
|
||||
>The Paper Pilot Community</a
|
||||
>
|
||||
<a href="https://discord.gg/yJ4fjnjU54" target="_blank">Profectus & Friends</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discord.gg/F3xveHV" target="_blank">The Modding Tree</a>
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Resource, displayResource } from "features/resources/resource";
|
|||
import type { GenericTree, GenericTreeNode, TreeNode, TreeNodeOptions } from "features/trees/tree";
|
||||
import { createTreeNode } from "features/trees/tree";
|
||||
import type { GenericFormula } from "game/formulas/types";
|
||||
import { BaseLayer } from "game/layers";
|
||||
import type { Modifier } from "game/modifiers";
|
||||
import type { Persistent } from "game/persistence";
|
||||
import { DefaultValue, persistent } from "game/persistence";
|
||||
|
@ -133,8 +134,8 @@ export function createResetButton<T extends ClickableOptions & ResetButtonOption
|
|||
{unref(resetButton.conversion.buyMax) ? "Next:" : "Req:"}{" "}
|
||||
{displayResource(
|
||||
resetButton.conversion.baseResource,
|
||||
!unref(resetButton.conversion.buyMax) ||
|
||||
Decimal.lt(unref(resetButton.conversion.actualGain), 1)
|
||||
!unref(resetButton.conversion.buyMax) &&
|
||||
Decimal.gte(unref(resetButton.conversion.actualGain), 1)
|
||||
? unref(resetButton.conversion.currentAt)
|
||||
: unref(resetButton.conversion.nextAt)
|
||||
)}{" "}
|
||||
|
@ -485,3 +486,22 @@ export function createFormulaPreview(
|
|||
return <>{formatSmall(formula.evaluate())}</>;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for getting a computed boolean for whether or not a given feature is currently rendered in the DOM.
|
||||
* Note it will have a true value even if the feature is off screen.
|
||||
* @param layer The layer the feature appears within
|
||||
* @param id The ID of the feature
|
||||
*/
|
||||
export function isRendered(layer: BaseLayer, id: string): ComputedRef<boolean>;
|
||||
/**
|
||||
* Utility function for getting a computed boolean for whether or not a given feature is currently rendered in the DOM.
|
||||
* Note it will have a true value even if the feature is off screen.
|
||||
* @param layer The layer the feature appears within
|
||||
* @param feature The feature that may be rendered
|
||||
*/
|
||||
export function isRendered(layer: BaseLayer, feature: { id: string }): ComputedRef<boolean>;
|
||||
export function isRendered(layer: BaseLayer, idOrFeature: string | { id: string }) {
|
||||
const id = typeof idOrFeature === "string" ? idOrFeature : idOrFeature.id;
|
||||
return computed(() => id in layer.nodes.value);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
color,
|
||||
reset
|
||||
}));
|
||||
addTooltip(treeNode, {
|
||||
const tooltip = addTooltip(treeNode, {
|
||||
display: createResourceTooltip(points),
|
||||
pinnable: true
|
||||
});
|
||||
|
@ -58,6 +58,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
|
|||
name,
|
||||
color,
|
||||
points,
|
||||
tooltip,
|
||||
display: jsx(() => (
|
||||
<>
|
||||
<MainDisplay resource={points} color={color} />
|
||||
|
|
|
@ -120,7 +120,7 @@ export default defineComponent({
|
|||
barStyle.clipPath = `inset(0% ${normalizedProgress.value}% 0% 0%)`;
|
||||
break;
|
||||
case Direction.Left:
|
||||
barStyle.clipPath = `inset(0% 0% 0% ${normalizedProgress.value} + '%)`;
|
||||
barStyle.clipPath = `inset(0% 0% 0% ${normalizedProgress.value}%)`;
|
||||
break;
|
||||
case Direction.Default:
|
||||
barStyle.clipPath = "inset(0% 50% 0% 0%)";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<line
|
||||
class="link"
|
||||
v-bind="link"
|
||||
v-bind="linkProps"
|
||||
:class="{ pulsing: link.pulsing }"
|
||||
:x1="startPosition.x"
|
||||
:y1="startPosition.y"
|
||||
|
@ -12,6 +12,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import type { BoardNode, BoardNodeLink } from "features/boards/board";
|
||||
import { kebabifyObject } from "util/vue";
|
||||
import { computed, toRefs, unref } from "vue";
|
||||
|
||||
const _props = defineProps<{
|
||||
|
@ -49,11 +50,14 @@ const endPosition = computed(() => {
|
|||
}
|
||||
return position;
|
||||
});
|
||||
|
||||
const linkProps = computed(() => kebabifyObject(_props.link as unknown as Record<string, unknown>));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.link {
|
||||
transition-duration: 0s;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.link.pulsing {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<line
|
||||
stroke-width="15px"
|
||||
stroke="white"
|
||||
v-bind="link"
|
||||
v-bind="linkProps"
|
||||
:x1="startPosition.x"
|
||||
:y1="startPosition.y"
|
||||
:x2="endPosition.x"
|
||||
|
@ -13,6 +13,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { Link } from "features/links/links";
|
||||
import type { FeatureNode } from "game/layers";
|
||||
import { kebabifyObject } from "util/vue";
|
||||
import { computed, toRefs } from "vue";
|
||||
|
||||
const _props = defineProps<{
|
||||
|
@ -54,4 +55,6 @@ const endPosition = computed(() => {
|
|||
}
|
||||
return position;
|
||||
});
|
||||
|
||||
const linkProps = computed(() => kebabifyObject(_props.link as unknown as Record<string, unknown>));
|
||||
</script>
|
||||
|
|
|
@ -95,18 +95,6 @@ export function addTooltip<T extends TooltipOptions>(
|
|||
}
|
||||
|
||||
nextTick(() => {
|
||||
if (options.pinnable) {
|
||||
if ("pinned" in element) {
|
||||
console.error(
|
||||
"Cannot add pinnable tooltip to element that already has a property called 'pinned'"
|
||||
);
|
||||
options.pinnable = false;
|
||||
deletePersistent(options.pinned as Persistent<boolean>);
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(element as any).pinned = options.pinned;
|
||||
}
|
||||
}
|
||||
const elementComponent = element[Component];
|
||||
element[Component] = TooltipComponent as GenericComponent;
|
||||
const elementGatherProps = element[GatherProps].bind(element);
|
||||
|
|
|
@ -345,19 +345,35 @@ export abstract class InternalFormula<T extends [FormulaSource] | FormulaSource[
|
|||
public static sgn = InternalFormula.sign;
|
||||
|
||||
public static round(value: FormulaSource) {
|
||||
return new Formula({ inputs: [value], evaluate: Decimal.round });
|
||||
return new Formula({
|
||||
inputs: [value],
|
||||
evaluate: Decimal.round,
|
||||
invert: ops.invertPassthrough
|
||||
});
|
||||
}
|
||||
|
||||
public static floor(value: FormulaSource) {
|
||||
return new Formula({ inputs: [value], evaluate: Decimal.floor });
|
||||
return new Formula({
|
||||
inputs: [value],
|
||||
evaluate: Decimal.floor,
|
||||
invert: ops.invertPassthrough
|
||||
});
|
||||
}
|
||||
|
||||
public static ceil(value: FormulaSource) {
|
||||
return new Formula({ inputs: [value], evaluate: Decimal.ceil });
|
||||
return new Formula({
|
||||
inputs: [value],
|
||||
evaluate: Decimal.ceil,
|
||||
invert: ops.invertPassthrough
|
||||
});
|
||||
}
|
||||
|
||||
public static trunc(value: FormulaSource) {
|
||||
return new Formula({ inputs: [value], evaluate: Decimal.trunc });
|
||||
return new Formula({
|
||||
inputs: [value],
|
||||
evaluate: Decimal.trunc,
|
||||
invert: ops.invertPassthrough
|
||||
});
|
||||
}
|
||||
|
||||
public static add<T extends GenericFormula>(value: T, other: FormulaSource): T;
|
||||
|
@ -459,7 +475,7 @@ export abstract class InternalFormula<T extends [FormulaSource] | FormulaSource[
|
|||
return new Formula({
|
||||
inputs: [value, min, max],
|
||||
evaluate: Decimal.clamp,
|
||||
invert: ops.passthrough as InvertFunction<[FormulaSource, FormulaSource, FormulaSource]>
|
||||
invert: ops.invertPassthrough
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1453,9 +1469,7 @@ export function calculateMaxAffordable(
|
|||
formula.invertIntegral(Decimal.add(resource.value, formula.evaluateIntegral()))
|
||||
).sub(unref(formula.innermostVariable) ?? 0);
|
||||
} else {
|
||||
affordable = Decimal.floor(
|
||||
formula.invert(resource.value)
|
||||
).add(1).sub(unref(formula.innermostVariable) ?? 0);
|
||||
affordable = Decimal.floor(formula.invert(resource.value));
|
||||
}
|
||||
}
|
||||
affordable = Decimal.clampMax(affordable, maxBulkAmount);
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import Decimal, { DecimalSource } from "util/bignum";
|
||||
import Formula, { hasVariable, unrefFormulaSource } from "./formulas";
|
||||
import { FormulaSource, GenericFormula, InvertFunction, SubstitutionStack } from "./types";
|
||||
import {
|
||||
FormulaSource,
|
||||
GenericFormula,
|
||||
InvertFunction,
|
||||
InvertibleFormula,
|
||||
SubstitutionStack
|
||||
} from "./types";
|
||||
|
||||
const ln10 = Decimal.ln(10);
|
||||
|
||||
|
@ -8,6 +14,15 @@ export function passthrough<T extends GenericFormula | DecimalSource>(value: T):
|
|||
return value;
|
||||
}
|
||||
|
||||
export function invertPassthrough(value: DecimalSource, ...inputs: FormulaSource[]) {
|
||||
const variable = inputs.find(input => hasVariable(input)) as InvertibleFormula | undefined;
|
||||
if (variable == null) {
|
||||
console.error("Could not invert due to no input being a variable");
|
||||
return 0;
|
||||
}
|
||||
return variable.invert(value);
|
||||
}
|
||||
|
||||
export function invertNeg(value: DecimalSource, lhs: FormulaSource) {
|
||||
if (hasVariable(lhs)) {
|
||||
return lhs.invert(Decimal.neg(value));
|
||||
|
|
|
@ -297,9 +297,9 @@ export function createSequentialModifier<
|
|||
getFormula: modifiers.every(m => m.getFormula != null)
|
||||
? (gain: FormulaSource) =>
|
||||
modifiers
|
||||
.filter(m => unref(m.enabled) !== false)
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
.reduce((acc, curr) => curr.getFormula!(acc), gain)
|
||||
.reduce((acc, curr) => Formula.if(acc, curr.enabled ?? true,
|
||||
acc => curr.getFormula!(acc), acc => acc), gain)
|
||||
: undefined,
|
||||
enabled: modifiers.some(m => m.enabled != null)
|
||||
? computed(() => modifiers.filter(m => unref(m.enabled) !== false).length > 0)
|
||||
|
|
|
@ -222,7 +222,7 @@ export function createCostRequirement<T extends CostRequirementOptions>(
|
|||
Decimal.gte(
|
||||
req.resource.value,
|
||||
unref(req.cost as ProcessedComputable<DecimalSource>)
|
||||
)
|
||||
) ? 1 : 0
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,11 @@ export function camelToTitle(camel: string): string {
|
|||
return title;
|
||||
}
|
||||
|
||||
export function camelToKebab(camel: string) {
|
||||
// Split off first character so function works on upper camel (pascal) case
|
||||
return (camel[0] + camel.slice(1).replace(/[A-Z]/g, c => `-${c}`)).toLowerCase();
|
||||
}
|
||||
|
||||
export function isFunction<T, S extends ReadonlyArray<unknown>, R>(
|
||||
functionOrValue: ((...args: S) => T) | R
|
||||
): functionOrValue is (...args: S) => T {
|
||||
|
|
|
@ -21,6 +21,7 @@ import {
|
|||
unref,
|
||||
watchEffect
|
||||
} from "vue";
|
||||
import { camelToKebab } from "./common";
|
||||
|
||||
export function coerceComponent(
|
||||
component: CoercableComponent,
|
||||
|
@ -241,3 +242,10 @@ export function trackHover(element: VueFeature): Ref<boolean> {
|
|||
|
||||
return isHovered;
|
||||
}
|
||||
|
||||
export function kebabifyObject(object: Record<string, unknown>) {
|
||||
return Object.keys(object).reduce((acc, curr) => {
|
||||
acc[camelToKebab(curr)] = object[curr];
|
||||
return acc;
|
||||
}, {} as Record<string, unknown>);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ describe("Creating conversion", () => {
|
|||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||
expect(unref(conversion.currentGain)).compare_tolerance(100);
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.currentGain)).compare_tolerance(0);
|
||||
});
|
||||
});
|
||||
describe("Calculates actualGain correctly", () => {
|
||||
let conversion: GenericConversion;
|
||||
|
@ -69,6 +73,10 @@ describe("Creating conversion", () => {
|
|||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||
expect(unref(conversion.actualGain)).compare_tolerance(100);
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.actualGain)).compare_tolerance(0);
|
||||
});
|
||||
});
|
||||
describe("Calculates currentAt correctly", () => {
|
||||
let conversion: GenericConversion;
|
||||
|
@ -95,6 +103,10 @@ describe("Creating conversion", () => {
|
|||
Decimal.pow(100, 2).times(10)
|
||||
);
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.currentAt)).compare_tolerance(0);
|
||||
});
|
||||
});
|
||||
describe("Calculates nextAt correctly", () => {
|
||||
let conversion: GenericConversion;
|
||||
|
@ -117,6 +129,10 @@ describe("Creating conversion", () => {
|
|||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(101, 2).times(10));
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.dTen);
|
||||
});
|
||||
});
|
||||
test("Converts correctly", () => {
|
||||
const conversion = createCumulativeConversion(() => ({
|
||||
|
@ -193,6 +209,10 @@ describe("Creating conversion", () => {
|
|||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||
expect(unref(conversion.currentGain)).compare_tolerance(100);
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.currentGain)).compare_tolerance(1);
|
||||
});
|
||||
});
|
||||
describe("Calculates actualGain correctly", () => {
|
||||
let conversion: GenericConversion;
|
||||
|
@ -216,6 +236,10 @@ describe("Creating conversion", () => {
|
|||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||
expect(unref(conversion.actualGain)).compare_tolerance(99);
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.actualGain)).compare_tolerance(0);
|
||||
});
|
||||
});
|
||||
describe("Calculates currentAt correctly", () => {
|
||||
let conversion: GenericConversion;
|
||||
|
@ -243,6 +267,10 @@ describe("Creating conversion", () => {
|
|||
Decimal.pow(100, 2).times(10)
|
||||
);
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.currentAt)).compare_tolerance(Decimal.pow(1, 2).times(10));
|
||||
});
|
||||
});
|
||||
describe("Calculates nextAt correctly", () => {
|
||||
let conversion: GenericConversion;
|
||||
|
@ -266,6 +294,10 @@ describe("Creating conversion", () => {
|
|||
baseResource.value = Decimal.pow(100, 2).times(10).add(1);
|
||||
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(101, 2).times(10));
|
||||
});
|
||||
test("Zero", () => {
|
||||
baseResource.value = Decimal.dZero;
|
||||
expect(unref(conversion.nextAt)).compare_tolerance(Decimal.pow(2, 2).times(10));
|
||||
});
|
||||
});
|
||||
test("Converts correctly", () => {
|
||||
const conversion = createIndependentConversion(() => ({
|
||||
|
|
|
@ -13,9 +13,13 @@ import { InvertibleIntegralFormula } from "game/formulas/types";
|
|||
|
||||
type FormulaFunctions = keyof GenericFormula & keyof typeof Formula & keyof typeof Decimal;
|
||||
|
||||
const testValues = [-1, "0", Decimal.dOne] as const;
|
||||
const testValues = [-2, "0", new Decimal(10.5)] as const;
|
||||
|
||||
const invertibleZeroParamFunctionNames = [
|
||||
"round",
|
||||
"floor",
|
||||
"ceil",
|
||||
"trunc",
|
||||
"neg",
|
||||
"recip",
|
||||
"log10",
|
||||
|
@ -48,10 +52,6 @@ const invertibleZeroParamFunctionNames = [
|
|||
const nonInvertibleZeroParamFunctionNames = [
|
||||
"abs",
|
||||
"sign",
|
||||
"round",
|
||||
"floor",
|
||||
"ceil",
|
||||
"trunc",
|
||||
"pLog10",
|
||||
"absLog10",
|
||||
"factorial",
|
||||
|
@ -85,6 +85,10 @@ const integrableZeroParamFunctionNames = [
|
|||
] as const;
|
||||
const nonIntegrableZeroParamFunctionNames = [
|
||||
...nonInvertibleZeroParamFunctionNames,
|
||||
"round",
|
||||
"floor",
|
||||
"ceil",
|
||||
"trunc",
|
||||
"lambertw",
|
||||
"ssqrt"
|
||||
] as const;
|
||||
|
@ -151,7 +155,7 @@ describe("Formula Equality Checking", () => {
|
|||
describe("Formula aliases", () => {
|
||||
function testAliases<T extends FormulaFunctions>(
|
||||
aliases: T[],
|
||||
args: Parameters<(typeof Formula)[T]>
|
||||
args: Parameters<typeof Formula[T]>
|
||||
) {
|
||||
describe(aliases[0], () => {
|
||||
let formula: GenericFormula;
|
||||
|
@ -246,7 +250,7 @@ describe("Creating Formulas", () => {
|
|||
|
||||
function checkFormula<T extends FormulaFunctions>(
|
||||
functionName: T,
|
||||
args: Readonly<Parameters<(typeof Formula)[T]>>
|
||||
args: Readonly<Parameters<typeof Formula[T]>>
|
||||
) {
|
||||
let formula: GenericFormula;
|
||||
beforeAll(() => {
|
||||
|
@ -270,7 +274,7 @@ describe("Creating Formulas", () => {
|
|||
// It's a lot of tests, but I'd rather be exhaustive
|
||||
function testFormulaCall<T extends FormulaFunctions>(
|
||||
functionName: T,
|
||||
args: Readonly<Parameters<(typeof Formula)[T]>>
|
||||
args: Readonly<Parameters<typeof Formula[T]>>
|
||||
) {
|
||||
if ((functionName === "slog" || functionName === "layeradd") && args[0] === -1) {
|
||||
// These cases in particular take a long time, so skip them
|
||||
|
@ -488,18 +492,18 @@ describe("Inverting", () => {
|
|||
});
|
||||
|
||||
test("Inverting nested formulas", () => {
|
||||
const formula = Formula.add(variable, constant).times(constant);
|
||||
const formula = Formula.add(variable, constant).times(constant).floor();
|
||||
expect(formula.invert(100)).compare_tolerance(0);
|
||||
});
|
||||
|
||||
describe("Inverting with non-invertible sections", () => {
|
||||
test("Non-invertible constant", () => {
|
||||
const formula = Formula.add(variable, constant.ceil());
|
||||
const formula = Formula.add(variable, constant.sign());
|
||||
expect(formula.isInvertible()).toBe(true);
|
||||
expect(() => formula.invert(10)).not.toLogError();
|
||||
});
|
||||
test("Non-invertible variable", () => {
|
||||
const formula = Formula.add(variable.ceil(), constant);
|
||||
const formula = Formula.add(variable.sign(), constant);
|
||||
expect(formula.isInvertible()).toBe(false);
|
||||
expect(() => formula.invert(10)).toLogError();
|
||||
});
|
||||
|
|
|
@ -83,7 +83,7 @@ describe("Creating cost requirement", () => {
|
|||
cost: 10,
|
||||
cumulativeCost: false
|
||||
}));
|
||||
expect(unref(requirement.requirementMet)).toBe(true);
|
||||
expect(unref(requirement.requirementMet)).toBe(1);
|
||||
});
|
||||
|
||||
test("Requirement not met when not meeting the cost", () => {
|
||||
|
@ -92,7 +92,7 @@ describe("Creating cost requirement", () => {
|
|||
cost: 100,
|
||||
cumulativeCost: false
|
||||
}));
|
||||
expect(unref(requirement.requirementMet)).toBe(false);
|
||||
expect(unref(requirement.requirementMet)).toBe(0);
|
||||
});
|
||||
|
||||
describe("canMaximize works correctly", () => {
|
||||
|
|
Loading…
Reference in a new issue