refactor: improve structure of src
This commit is contained in:
parent
b74919b75b
commit
c5d4ec1abd
96 changed files with 146 additions and 157 deletions
131
src/dice/check-evaluation.ts
Normal file
131
src/dice/check-evaluation.ts
Normal file
|
@ -0,0 +1,131 @@
|
|||
// SPDX-FileCopyrightText: 2021 Johannes Loher
|
||||
// SPDX-FileCopyrightText: 2021 Oliver Rümpelein
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { getGame } from "../utils/utils";
|
||||
|
||||
export function evaluateCheck(
|
||||
dice: number[],
|
||||
checkTargetNumber: number,
|
||||
{
|
||||
maximumCoupResult = 1,
|
||||
minimumFumbleResult = 20,
|
||||
canFumble = true,
|
||||
}: { maximumCoupResult?: number; minimumFumbleResult?: number; canFumble?: boolean } = {},
|
||||
): SubCheckResult[] {
|
||||
const diceWithSubChecks = assignSubChecksToDice(dice, checkTargetNumber, {
|
||||
maximumCoupResult: maximumCoupResult,
|
||||
});
|
||||
return evaluateDiceWithSubChecks(diceWithSubChecks, {
|
||||
maximumCoupResult: maximumCoupResult,
|
||||
minimumFumbleResult: minimumFumbleResult,
|
||||
canFumble: canFumble,
|
||||
});
|
||||
}
|
||||
|
||||
interface DieWithSubCheck {
|
||||
result: number;
|
||||
checkTargetNumber: number;
|
||||
}
|
||||
|
||||
function assignSubChecksToDice(
|
||||
dice: number[],
|
||||
checkTargetNumber: number,
|
||||
{
|
||||
maximumCoupResult = 1,
|
||||
}: {
|
||||
maximumCoupResult?: number;
|
||||
} = {},
|
||||
): DieWithSubCheck[] {
|
||||
const requiredNumberOfDice = getRequiredNumberOfDice(checkTargetNumber);
|
||||
|
||||
if (dice.length !== requiredNumberOfDice || requiredNumberOfDice < 1) {
|
||||
throw new Error(getGame().i18n.localize("DS4.ErrorInvalidNumberOfDice"));
|
||||
}
|
||||
|
||||
const checkTargetNumberForLastSubCheck = checkTargetNumber - 20 * (requiredNumberOfDice - 1);
|
||||
|
||||
const indexOfSmallestNonCoup = findIndexOfSmallestNonCoup(dice, maximumCoupResult);
|
||||
const indexOfFirstCoup = dice.findIndex((die) => die <= maximumCoupResult);
|
||||
const indexForLastSubCheck = shouldUseCoupForLastSubCheck(
|
||||
indexOfSmallestNonCoup,
|
||||
indexOfFirstCoup,
|
||||
dice,
|
||||
checkTargetNumberForLastSubCheck,
|
||||
)
|
||||
? indexOfFirstCoup
|
||||
: indexOfSmallestNonCoup;
|
||||
|
||||
return dice.map((die, index) => ({
|
||||
result: die,
|
||||
checkTargetNumber: index === indexForLastSubCheck ? checkTargetNumberForLastSubCheck : 20,
|
||||
}));
|
||||
}
|
||||
|
||||
function findIndexOfSmallestNonCoup(dice: number[], maximumCoupResult: number): number {
|
||||
return dice
|
||||
.map((die, index): [number, number] => [die, index])
|
||||
.filter((indexedDie) => indexedDie[0] > maximumCoupResult)
|
||||
.reduce(
|
||||
(smallestIndexedDie, indexedDie) =>
|
||||
indexedDie[0] < smallestIndexedDie[0] ? indexedDie : smallestIndexedDie,
|
||||
[Infinity, -1],
|
||||
)[1];
|
||||
}
|
||||
|
||||
function shouldUseCoupForLastSubCheck(
|
||||
indexOfSmallestNonCoup: number,
|
||||
indexOfFirstCoup: number,
|
||||
dice: readonly number[],
|
||||
checkTargetNumberForLastSubCheck: number,
|
||||
) {
|
||||
if (indexOfFirstCoup !== -1 && indexOfSmallestNonCoup === -1) {
|
||||
return true;
|
||||
}
|
||||
const smallestNonCoup = dice[indexOfSmallestNonCoup];
|
||||
if (
|
||||
!Number.isInteger(indexOfFirstCoup) ||
|
||||
indexOfFirstCoup < -1 ||
|
||||
!Number.isInteger(indexOfSmallestNonCoup) ||
|
||||
smallestNonCoup === undefined
|
||||
) {
|
||||
throw new Error("Received an invalid value for the parameter indexOfSmallestNonCoup or indexOfFirstCoup,");
|
||||
}
|
||||
return (
|
||||
indexOfFirstCoup !== -1 &&
|
||||
smallestNonCoup > checkTargetNumberForLastSubCheck &&
|
||||
smallestNonCoup + checkTargetNumberForLastSubCheck > 20
|
||||
);
|
||||
}
|
||||
|
||||
interface SubCheckResult extends DieWithSubCheck, DiceTerm.Result {}
|
||||
|
||||
function evaluateDiceWithSubChecks(
|
||||
results: DieWithSubCheck[],
|
||||
{
|
||||
maximumCoupResult,
|
||||
minimumFumbleResult,
|
||||
canFumble,
|
||||
}: { maximumCoupResult: number; minimumFumbleResult: number; canFumble: boolean },
|
||||
): SubCheckResult[] {
|
||||
return results.map((dieWithSubCheck, index) => {
|
||||
const result: SubCheckResult = {
|
||||
...dieWithSubCheck,
|
||||
active: dieWithSubCheck.result <= dieWithSubCheck.checkTargetNumber,
|
||||
discarded: dieWithSubCheck.result > dieWithSubCheck.checkTargetNumber,
|
||||
};
|
||||
if (result.result <= maximumCoupResult) {
|
||||
result.success = true;
|
||||
result.count = result.checkTargetNumber;
|
||||
result.active = true;
|
||||
result.discarded = false;
|
||||
}
|
||||
if (index === 0 && canFumble && result.result >= minimumFumbleResult) result.failure = true;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
export function getRequiredNumberOfDice(checkTargetNumber: number): number {
|
||||
return Math.max(Math.ceil(checkTargetNumber / 20), 1);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue