Skip to content

Commit

Permalink
Go back to dynamic types (#635)
Browse files Browse the repository at this point in the history
  • Loading branch information
alxjrvs authored Sep 24, 2024
1 parent 0aceef3 commit 23273cf
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 68 deletions.
4 changes: 2 additions & 2 deletions src/D.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isCustomSidesArg } from '~guards'
import { isCustomSidesStringArg } from '~guards'
import { DicePoolType } from '~types'

type Type<T> = T extends string[] ? DicePoolType.custom : DicePoolType.numerical
Expand All @@ -11,7 +11,7 @@ class D<Sides extends string[] | number> {
type: Type<Sides>

constructor(sides: Sides) {
if (isCustomSidesArg(sides)) {
if (isCustomSidesStringArg(sides)) {
this.sides = sides.length
this.type = DicePoolType.custom as Type<Sides>
this.faces = sides as Faces<Sides>
Expand Down
2 changes: 1 addition & 1 deletion src/guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
4 changes: 3 additions & 1 deletion src/models/ArgumentsModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import {
import { NotationModel, OptionsModel } from '~models'
import { D } from '~src/D'

function formDicePools(args: RandsumRollArgument[]): DicePools {
function formDicePools<Sides extends string | number = string | number>(
args: RandsumRollArgument<Sides>[]
): DicePools<Sides> {
return {
dicePools: args.reduce(
(acc, arg) => ({ ...acc, [uuid()]: parameterize(arg) }),
Expand Down
54 changes: 31 additions & 23 deletions src/models/DicePoolsModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | number>['dicePools']
): DicePoolType {
switch (true) {
case Object.values(dicePools).every(
(pool) => typeof pool.options.sides === 'number'
Expand All @@ -19,48 +21,54 @@ function calculateType(dicePools: DicePools['dicePools']): DicePoolType {
}
}

function calculateTotal(rolls: number[] | string[], bonus = 0): number {
function calculateTotal<Sides extends string | number = string | number>(
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<Sides>,
rawRolls: RandsumRollResult<Sides>['rawRolls']
): RandsumRollResult<Sides>['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<Sides>['modifiedRolls']
}

function generateRollResult(DicePools: DicePools): RandsumRollResult {
const rawRolls = RawRollsModel.generate(DicePools.dicePools)
const modifiedRolls = generateModifiedRolls(DicePools, rawRolls)
function generateRollResult<Sides extends string | number = string | number>(
dicePools: DicePools<Sides>
): RandsumRollResult<Sides> {
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 {
Expand Down
4 changes: 2 additions & 2 deletions src/models/NotationModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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)
Expand Down
29 changes: 13 additions & 16 deletions src/models/ParametersModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,33 @@ import {
applySingleCap
} from './modifierApplicators'

type RollBonuses = {
rolls: number[]
type RollBonuses<Sides extends string | number = string | number> = {
rolls: Sides[]
simpleMathModifier: number
}

type ModifiedRollBonuses = {
rolls: string[]
simpleMathModifier: 0
}
function applyModifiers(
poolParameters: RandsumRollParameters<string> | RandsumRollParameters<number>,
initialRolls: number[] | string[]
): RollBonuses | ModifiedRollBonuses {
function applyModifiers<Sides extends string | number = string | number>(
poolParameters: RandsumRollParameters<Sides>,
initialRolls: Sides[]
): RollBonuses<Sides> {
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<number>

const rollOne: () => number = () => poolParameters.die.roll()
const rollOne: () => number = () => die.roll()

return Object.keys(modifiers).reduce((bonuses, key) => {
switch (key) {
Expand Down Expand Up @@ -111,7 +108,7 @@ function applyModifiers(
default:
throw new Error(`Unknown modifier: ${key}`)
}
}, rollBonuses)
}, rollBonuses) as RollBonuses<Sides>
}

export default { applyModifiers }
8 changes: 4 additions & 4 deletions src/models/RawRollsModel.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { DicePools, RandsumRollResult } from '~types'

function generate(
dicePools: DicePools['dicePools']
): RandsumRollResult['rawRolls'] {
function generate<Sides extends string | number = string | number>(
dicePools: DicePools<Sides>['dicePools']
): RandsumRollResult<Sides>['rawRolls'] {
return Object.fromEntries(
Object.keys(dicePools).map((key) => {
const {
Expand All @@ -14,7 +14,7 @@ function generate(
length: quantity || 1
},
() => die.roll()
) as string[] | number[]
) as Sides[]
return [key, rolls]
})
)
Expand Down
21 changes: 19 additions & 2 deletions src/roll.ts
Original file line number Diff line number Diff line change
@@ -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<number, DicePoolType.numerical>
function roll(
...args: RandsumCustomArgument[]
): RandsumRollResult<string, DicePoolType.custom>
function roll(
...args: RandsumRollArgument<string | number>[]
): RandsumRollResult<string | number, DicePoolType.mixed, string>
function roll<Sides extends string | number = string | number>(
...args: RandsumRollArgument<Sides>[]
): RandsumRollResult<Sides> {
const dicePools = ArgumentsModel.formDicePools(args)
return DicePoolsModel.generateRollResult(dicePools)
}
Expand Down
45 changes: 30 additions & 15 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { D } from './D'

// Primitives

type DiceNotationWithNumericSides = `${number}${'d' | 'D'}${number}${string}`
type DiceNotationWithCustomSides = `${number}${'d' | 'D'}{${string}}`

Expand All @@ -16,6 +17,7 @@ export enum DicePoolType {
}

// Options

export interface RandsumRollOptions<
Sides extends string | number = string | number
> {
Expand Down Expand Up @@ -72,48 +74,61 @@ export type RequiredCoreDiceParameters<

// Arguments

export type RandsumRollArgument =
export type RandsumNumericalArgument =
| `${number}`
| number
| D<string[] | number>
| RandsumRollOptions
| RandsumNotation
| D<number>
| RandsumRollOptions<number>
| RandsumNotation<number>

export type RandsumCustomArgument =
| D<string[]>
| RandsumRollOptions<string>
| RandsumNotation<string>
| 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<Sides>
options: RandsumRollOptions<Sides>
die: D<Sides extends string ? string[] : number>
notation: RandsumNotation<Sides>
description: string[]
}

export interface DicePools {
export interface DicePools<Sides extends string | number = string | number> {
dicePools: {
[key: string]: RandsumRollParameters
[key: string]: RandsumRollParameters<Sides>
}
}

// 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<Sides> {
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 {
Expand Down
4 changes: 2 additions & 2 deletions tests/DicePoolsModel.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]
})
Expand Down

0 comments on commit 23273cf

Please sign in to comment.