From 23273cf39a216a7a8d9c7e8319dab05a38896ded Mon Sep 17 00:00:00 2001 From: Alex Jarvis Date: Tue, 24 Sep 2024 08:47:42 -0400 Subject: [PATCH] Go back to dynamic types (#635) --- src/D.ts | 4 +-- src/guards.ts | 2 +- src/models/ArgumentsModel/index.ts | 4 ++- src/models/DicePoolsModel/index.ts | 54 +++++++++++++++++------------ src/models/NotationModel/index.ts | 4 +-- src/models/ParametersModel/index.ts | 29 +++++++--------- src/models/RawRollsModel.ts | 8 ++--- src/roll.ts | 21 +++++++++-- src/types.ts | 45 ++++++++++++++++-------- tests/DicePoolsModel.test.ts | 4 +-- 10 files changed, 107 insertions(+), 68 deletions(-) diff --git a/src/D.ts b/src/D.ts index b60ea3e7..982cb2dc 100644 --- a/src/D.ts +++ b/src/D.ts @@ -1,4 +1,4 @@ -import { isCustomSidesArg } from '~guards' +import { isCustomSidesStringArg } from '~guards' import { DicePoolType } from '~types' type Type = T extends string[] ? DicePoolType.custom : DicePoolType.numerical @@ -11,7 +11,7 @@ class D { type: Type constructor(sides: Sides) { - if (isCustomSidesArg(sides)) { + if (isCustomSidesStringArg(sides)) { this.sides = sides.length this.type = DicePoolType.custom as Type this.faces = sides as Faces diff --git a/src/guards.ts b/src/guards.ts index 41c97666..1a13b643 100644 --- a/src/guards.ts +++ b/src/guards.ts @@ -21,7 +21,7 @@ export function isDiceNotationArg( return cleanArg.replace(completeRollPattern, '').length === 0 } -export function isCustomSidesArg( +export function isCustomSidesStringArg( argument: RandsumRollArgument ): argument is string[] { return ( diff --git a/src/models/ArgumentsModel/index.ts b/src/models/ArgumentsModel/index.ts index 947d9719..561a091a 100644 --- a/src/models/ArgumentsModel/index.ts +++ b/src/models/ArgumentsModel/index.ts @@ -14,7 +14,9 @@ import { import { NotationModel, OptionsModel } from '~models' import { D } from '~src/D' -function formDicePools(args: RandsumRollArgument[]): DicePools { +function formDicePools( + args: RandsumRollArgument[] +): DicePools { return { dicePools: args.reduce( (acc, arg) => ({ ...acc, [uuid()]: parameterize(arg) }), diff --git a/src/models/DicePoolsModel/index.ts b/src/models/DicePoolsModel/index.ts index a5b02331..1184b1c8 100644 --- a/src/models/DicePoolsModel/index.ts +++ b/src/models/DicePoolsModel/index.ts @@ -2,7 +2,9 @@ import { isFullNumArray } from '~guards' import { ParametersModel, RawRollsModel } from '~models' import { DicePools, DicePoolType, RandsumRollResult } from '~types' -function calculateType(dicePools: DicePools['dicePools']): DicePoolType { +function calculateType( + dicePools: DicePools['dicePools'] +): DicePoolType { switch (true) { case Object.values(dicePools).every( (pool) => typeof pool.options.sides === 'number' @@ -19,48 +21,54 @@ function calculateType(dicePools: DicePools['dicePools']): DicePoolType { } } -function calculateTotal(rolls: number[] | string[], bonus = 0): number { +function calculateTotal( + rolls: Sides[], + bonus = 0 +): Sides { if (isFullNumArray(rolls)) { - return rolls.reduce((acc, cur) => acc + cur, bonus) + return rolls.reduce( + (acc, cur) => (acc as number) + (cur as number), + bonus + ) as Sides } - return 0 + + return rolls.flat().join(', ') as Sides } -export function generateModifiedRolls( - DicePools: DicePools, - rawRolls: RandsumRollResult['rawRolls'] -): RandsumRollResult['modifiedRolls'] { +export function generateModifiedRolls< + Sides extends string | number = string | number +>( + DicePools: DicePools, + rawRolls: RandsumRollResult['rawRolls'] +): RandsumRollResult['modifiedRolls'] { return Object.fromEntries( Object.keys(DicePools.dicePools).map((key) => { const params = DicePools.dicePools[key] - const rolls = rawRolls[key] - const modified = ParametersModel.applyModifiers(params, rolls) + const modified = ParametersModel.applyModifiers(params, rawRolls[key]) const modifiedRoll = { rolls: modified.rolls, total: calculateTotal(modified.rolls, modified.simpleMathModifier) } return [key, modifiedRoll] }) - ) + ) as RandsumRollResult['modifiedRolls'] } -function generateRollResult(DicePools: DicePools): RandsumRollResult { - const rawRolls = RawRollsModel.generate(DicePools.dicePools) - const modifiedRolls = generateModifiedRolls(DicePools, rawRolls) +function generateRollResult( + dicePools: DicePools +): RandsumRollResult { + const rawRolls = RawRollsModel.generate(dicePools.dicePools) + const modifiedRolls = generateModifiedRolls(dicePools, rawRolls) const modifiedValues = Object.values(modifiedRolls) - const rawResult = Object.values(rawRolls) - const result = modifiedValues.map((pool) => pool.rolls) - const total = calculateTotal(modifiedValues.map((pool) => pool.total)) - const type = calculateType(DicePools.dicePools) return { - ...DicePools, + ...dicePools, rawRolls, - rawResult, modifiedRolls, - result, - type, - total + rawResult: Object.values(rawRolls), + result: modifiedValues.map((pool) => pool.rolls), + type: calculateType(dicePools.dicePools), + total: calculateTotal(modifiedValues.map((pool) => pool.total)) } } export default { diff --git a/src/models/NotationModel/index.ts b/src/models/NotationModel/index.ts index ea149fad..b659685b 100644 --- a/src/models/NotationModel/index.ts +++ b/src/models/NotationModel/index.ts @@ -6,7 +6,7 @@ import { RandsumRollOptions } from '~types' import { parseCoreNotation, parseModifiers } from './optionsParsers' -import { isDiceNotationArg, isCustomSidesArg } from '~guards' +import { isDiceNotationArg, isCustomSidesStringArg } from '~guards' import { OptionsModel } from '~models' function toOptions( @@ -35,7 +35,7 @@ function validate(notation: string): RandsumNotationValidationResult { valid: true, digested, notation: OptionsModel.toNotation(digested), - type: isCustomSidesArg(digested.sides) + type: isCustomSidesStringArg(digested.sides) ? DicePoolType.custom : DicePoolType.numerical, description: OptionsModel.toDescription(digested) diff --git a/src/models/ParametersModel/index.ts b/src/models/ParametersModel/index.ts index b81d81b5..7c0b4b66 100644 --- a/src/models/ParametersModel/index.ts +++ b/src/models/ParametersModel/index.ts @@ -9,36 +9,33 @@ import { applySingleCap } from './modifierApplicators' -type RollBonuses = { - rolls: number[] +type RollBonuses = { + rolls: Sides[] simpleMathModifier: number } -type ModifiedRollBonuses = { - rolls: string[] - simpleMathModifier: 0 -} -function applyModifiers( - poolParameters: RandsumRollParameters | RandsumRollParameters, - initialRolls: number[] | string[] -): RollBonuses | ModifiedRollBonuses { +function applyModifiers( + poolParameters: RandsumRollParameters, + initialRolls: Sides[] +): RollBonuses { if (isCustomParameters(poolParameters)) { return { simpleMathModifier: 0, - rolls: initialRolls as string[] + rolls: initialRolls } } - const rollBonuses: RollBonuses = { + const rollBonuses = { simpleMathModifier: 0, rolls: initialRolls as number[] } const { - options: { sides, quantity, modifiers = {} } - } = poolParameters + options: { sides, quantity, modifiers = {} }, + die + } = poolParameters as RandsumRollParameters - const rollOne: () => number = () => poolParameters.die.roll() + const rollOne: () => number = () => die.roll() return Object.keys(modifiers).reduce((bonuses, key) => { switch (key) { @@ -111,7 +108,7 @@ function applyModifiers( default: throw new Error(`Unknown modifier: ${key}`) } - }, rollBonuses) + }, rollBonuses) as RollBonuses } export default { applyModifiers } diff --git a/src/models/RawRollsModel.ts b/src/models/RawRollsModel.ts index 50a9141e..54bd3936 100644 --- a/src/models/RawRollsModel.ts +++ b/src/models/RawRollsModel.ts @@ -1,8 +1,8 @@ import { DicePools, RandsumRollResult } from '~types' -function generate( - dicePools: DicePools['dicePools'] -): RandsumRollResult['rawRolls'] { +function generate( + dicePools: DicePools['dicePools'] +): RandsumRollResult['rawRolls'] { return Object.fromEntries( Object.keys(dicePools).map((key) => { const { @@ -14,7 +14,7 @@ function generate( length: quantity || 1 }, () => die.roll() - ) as string[] | number[] + ) as Sides[] return [key, rolls] }) ) diff --git a/src/roll.ts b/src/roll.ts index fc853aee..1a3f3094 100644 --- a/src/roll.ts +++ b/src/roll.ts @@ -1,7 +1,24 @@ import { ArgumentsModel, DicePoolsModel } from '~models' -import { RandsumRollArgument, RandsumRollResult } from '~types' +import { + DicePoolType, + RandsumCustomArgument, + RandsumNumericalArgument, + RandsumRollArgument, + RandsumRollResult +} from '~types' -function roll(...args: RandsumRollArgument[]): RandsumRollResult { +function roll( + ...args: RandsumNumericalArgument[] +): RandsumRollResult +function roll( + ...args: RandsumCustomArgument[] +): RandsumRollResult +function roll( + ...args: RandsumRollArgument[] +): RandsumRollResult +function roll( + ...args: RandsumRollArgument[] +): RandsumRollResult { const dicePools = ArgumentsModel.formDicePools(args) return DicePoolsModel.generateRollResult(dicePools) } diff --git a/src/types.ts b/src/types.ts index 494f1a6f..7ca3df0f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,7 @@ import { D } from './D' // Primitives + type DiceNotationWithNumericSides = `${number}${'d' | 'D'}${number}${string}` type DiceNotationWithCustomSides = `${number}${'d' | 'D'}{${string}}` @@ -16,6 +17,7 @@ export enum DicePoolType { } // Options + export interface RandsumRollOptions< Sides extends string | number = string | number > { @@ -72,48 +74,61 @@ export type RequiredCoreDiceParameters< // Arguments -export type RandsumRollArgument = +export type RandsumNumericalArgument = | `${number}` | number - | D - | RandsumRollOptions - | RandsumNotation + | D + | RandsumRollOptions + | RandsumNotation + +export type RandsumCustomArgument = + | D + | RandsumRollOptions + | RandsumNotation | string[] +export type RandsumRollArgument< + Sides extends string | number = string | number +> = Sides extends string ? RandsumCustomArgument : RandsumNumericalArgument + // Parameters export interface RandsumRollParameters< Sides extends string | number = string | number > { - argument: RandsumRollArgument + argument: RandsumRollArgument options: RandsumRollOptions die: D notation: RandsumNotation description: string[] } -export interface DicePools { +export interface DicePools { dicePools: { - [key: string]: RandsumRollParameters + [key: string]: RandsumRollParameters } } // Results -export interface RandsumRollResult extends DicePools { +export interface RandsumRollResult< + Sides extends string | number = string | number, + DP extends DicePoolType = DicePoolType, + Total extends Sides = Sides +> extends DicePools { rawRolls: { - [key: string]: string[] | number[] + [key: string]: Sides[] } modifiedRolls: { [key: string]: { - rolls: string[] | number[] - total: number + rolls: Sides[] + total: Sides } } - result: (string | number)[][] - rawResult: (string | number)[][] - type: DicePoolType - total: number + result: Sides[][] + rawResult: Sides[][] + type: DP + total: Total } export interface RandsumNotationValidationResult { diff --git a/tests/DicePoolsModel.test.ts b/tests/DicePoolsModel.test.ts index 2ca0ff73..9c06d6de 100644 --- a/tests/DicePoolsModel.test.ts +++ b/tests/DicePoolsModel.test.ts @@ -197,10 +197,10 @@ describe('DicePoolsModel.generateResult', () => { modifiedRolls: { 'test-roll-id': { rolls: customSidesRoll, - total: 0 + total: 'r, a, n, d' } }, - total: 0, + total: 'r, a, n, d', type: DicePoolType.custom, result: [customSidesRoll] })