Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstream formula- and pando-related changes #1235

Merged
merged 30 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
56bea2c
Override nodes for `dynTag` in `detach`
lantua Jul 1, 2023
669236b
- Add `optimization` docs
lantua Jul 1, 2023
8866166
Improve `Node` generic tracking
lantua Jul 1, 2023
6e80a1a
Daily dose of linter god's blood sacrifice
lantua Jul 1, 2023
5fff00c
Merge branch 'master' into formula
lantua Jul 2, 2023
fca4b6d
`Read.accu` => `Read.ex`
lantua Jul 2, 2023
2d2fa97
type fix
lantua Jul 2, 2023
7c9ec09
- Implement `lookup` for `compile`
lantua Jul 6, 2023
efcb9c9
`Data` -> `TaggedFormula`
lantua Jul 6, 2023
60d1db5
The Great Renaming
lantua Jul 6, 2023
8523b6c
- Update `Read._withAll`
lantua Jul 6, 2023
a12aa5c
Add scaffolding for `sr-formula`
lantua Jul 6, 2023
044ba2d
- Update `TagMapNodeEntry` and `TagMapNodeEntries`
lantua Jul 6, 2023
bf80516
lint
lantua Jul 6, 2023
8a3b3c3
- Simplify `TypedRead`
lantua Jul 7, 2023
9ce4a71
Readjust `Read.ex` and `Read.accu`
lantua Jul 7, 2023
1ae2256
- Update `allBoolConditional` API
lantua Jul 7, 2023
d94e850
- Add `printEntry`
lantua Jul 7, 2023
cb2982e
Override `Read.toString` for `gi-formula`
lantua Jul 8, 2023
661a993
Merge branch 'master' into formula
lantua Jul 8, 2023
eed5914
- lint
lantua Jul 8, 2023
9f32e55
- Add `DebugCalculator` for `gi-formula`
lantua Jul 9, 2023
726ef49
- Update `Calculator` function argument types
lantua Jul 9, 2023
8f971c2
Stop using external `util`
lantua Jul 9, 2023
bd420c8
Minor refactoring
lantua Jul 9, 2023
a88b1c7
linting is a lie
lantua Jul 9, 2023
2b4d783
Merge branch 'master' into formula
lantua Jul 13, 2023
780c9f3
Minor type update
lantua Jul 14, 2023
d6f4bdc
Merge branch 'master' into formula
lantua Jul 15, 2023
c9cc2f3
Merge branch 'master' into formula
lantua Jul 16, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 21 additions & 15 deletions libs/gi-formula/src/calculator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { AnyOP, CalcResult } from '@genshin-optimizer/pando'
import { calculation, Calculator as Base } from '@genshin-optimizer/pando'
import type { AnyNode, CalcResult } from '@genshin-optimizer/pando'
import { Calculator as Base, calculation } from '@genshin-optimizer/pando'
import { assertUnreachable } from '@genshin-optimizer/util'
import type { Tag } from './data/util'
import { self } from './data/util'

Expand All @@ -14,21 +15,15 @@ export type CalcMeta = {

export class Calculator extends Base<CalcMeta> {
override computeCustom(val: any[], op: string): any {
if (op == 'res') {
const [preRes] = val as [number]
if (preRes >= 0.75) return 1 / (1 + 4 * preRes)
if (preRes >= 0) return 1 - preRes
return 1 - 0.5 * preRes
}
if (op == 'res') return res(val[0])
return super.computeCustom(val, op)
}
override computeMeta(
op: Exclude<AnyOP, 'read'>,
tag: Tag | undefined,
val: any,
x: (CalcResult<any, CalcMeta> | undefined)[],
_br: CalcResult<any, CalcMeta>[],
ex: any
{ op, ex }: AnyNode,
val: number | string,
x: (CalcResult<number | string, CalcMeta> | undefined)[],
_br: CalcResult<number | string, CalcMeta>[],
tag: Tag | undefined
): CalcMeta {
const preConds = [
tag?.qt === 'cond' ? [tag] : [],
Expand All @@ -40,6 +35,10 @@ export class Calculator extends Base<CalcMeta> {
return { tag, op: 'const', ops: [], conds }
}

if (op === 'read' && ex !== undefined) {
op = ex
ex = undefined
}
switch (op) {
case 'sum':
case 'prod':
Expand All @@ -62,13 +61,15 @@ export class Calculator extends Base<CalcMeta> {
}

case 'const':
case 'vtag':
case 'subscript':
return constOverride()
case 'match':
case 'thres':
case 'lookup':
return { ...x.find((x) => x)!.meta, conds }
case 'tag':
case 'read':
case 'dtag': {
const { tag: baseTag, op, ops } = x[0]!.meta
return { tag: baseTag ?? tag, op, ops, conds }
Expand All @@ -80,7 +81,7 @@ export class Calculator extends Base<CalcMeta> {
}
return constOverride()
default:
throw new Error('Should not reach this point')
assertUnreachable(op)
}
}

Expand All @@ -100,3 +101,8 @@ export class Calculator extends Base<CalcMeta> {
.filter((x) => x.q)
}
}
export function res(x: number): number {
if (x >= 0.75) return 1 / (1 + 4 * x)
if (x >= 0) return 1 - x
return 1 - 0.5 * x
}
6 changes: 3 additions & 3 deletions libs/gi-formula/src/data/artifact/NoblesseOblige.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ArtifactSetKey } from '@genshin-optimizer/consts'
import { cmpEq, cmpGE } from '@genshin-optimizer/pando'
import { cmpGE } from '@genshin-optimizer/pando'
import {
allBoolConditionals,
allStacks,
Expand All @@ -18,6 +18,6 @@ export default registerArt(
name,
selfBuff.premod.dmg_.burst.add(cmpGE(count, 2, percent(0.2))),

canNO4.in.add(set4.ifOn(cmpGE(count, 4, 1))),
teamBuff.premod.atk_.add(cmpEq(canNO4.out, 1, percent(0.2)))
canNO4.add(set4.ifOn(cmpGE(count, 4, 1))),
teamBuff.premod.atk_.add(canNO4.apply(percent(0.2)))
)
4 changes: 2 additions & 2 deletions libs/gi-formula/src/data/artifact/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Data } from '../util'
import type { TagMapNodeEntries } from '../util'
import NoblesseOblige from './NoblesseOblige'

const data: Data[] = [NoblesseOblige]
const data: TagMapNodeEntries[] = [NoblesseOblige]
export default data.flat()
12 changes: 6 additions & 6 deletions libs/gi-formula/src/data/artifact/util.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import type { ArtifactSetKey } from '@genshin-optimizer/consts'
import type { NumNode } from '@genshin-optimizer/pando'
import type { Data } from '../util'
import type { TagMapNodeEntries, TagMapNodeEntry } from '../util'
import { self, tag } from '../util'

export function registerArt(
src: ArtifactSetKey,
...data: (Data | Data[number])[]
): Data {
...data: (TagMapNodeEntry | TagMapNodeEntries)[]
): TagMapNodeEntries {
/* Unlike character and weapon, artifact buff is all-or-nothing, so we can register every
* buff as `src:art` and tag the formula as `src:src`. This means that `src:art`, which is
* read on each `et:agg`, does not need to reread `src:src`. This greatly reduce `Read`
* traffic due to the sheer numbers of `et:agg` calculations and `src:src` it would require
* for each `src:art` read.
*/

function internal({ tag: oldTag, value }: Data[number]): Data[number] {
function internal({ tag: oldTag, value }: TagMapNodeEntry): TagMapNodeEntry {
if (oldTag.src === src)
// Special entries (usually stack count) that override `stack`
return { tag: oldTag, value }
Expand All @@ -31,6 +31,6 @@ export function registerArt(
)
}

export function artCount(name: ArtifactSetKey): NumNode {
return self.common.count.with('src', name)
export function artCount(src: ArtifactSetKey): NumNode {
return self.common.count.src(src)
}
2 changes: 1 addition & 1 deletion libs/gi-formula/src/data/char/Nilou.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const {
const { a1AfterSkill, a1AfterHit, c4AfterPirHit } = allBoolConditionals(
info.key
)
const { c2Hydro, c2Dendro } = allConditionals(info.key, 'none')
const { c2Hydro, c2Dendro } = allConditionals(info.key, 'unique')

const onlyDendroHydroTeam = cmpGE(
team.common.count.dendro,
Expand Down
4 changes: 2 additions & 2 deletions libs/gi-formula/src/data/char/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Data } from '../util'
import type { TagMapNodeEntries } from '../util'
import Candace from './Candace'
import Nahida from './Nahida'
import Nilou from './Nilou'

const data: Data[] = [Candace, Nahida, Nilou]
const data: TagMapNodeEntries[] = [Candace, Nahida, Nilou]
export default data.flat()
18 changes: 9 additions & 9 deletions libs/gi-formula/src/data/char/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { locCharKeyToCharKey } from '@genshin-optimizer/consts'
import type { CharacterDataGen } from '@genshin-optimizer/gi-stats'
import type { NumNode } from '@genshin-optimizer/pando'
import { prod, subscript, sum } from '@genshin-optimizer/pando'
import type { Data, FormulaArg, Stat } from '../util'
import type { TagMapNodeEntries, FormulaArg, Stat } from '../util'
import {
addStatCurve,
allStatics,
Expand Down Expand Up @@ -46,8 +46,8 @@ export function dmg(
levelScaling: number[],
move: Exclude<MoveKey, 'elemental'>,
arg: { ele?: ElementWithPhyKey; baseMulti?: NumNode } & FormulaArg = {},
...extra: Data
): Data {
...extra: TagMapNodeEntries
): TagMapNodeEntries {
let { ele } = arg
if (!ele)
switch (move) {
Expand Down Expand Up @@ -93,8 +93,8 @@ export function shield(
flat: number[],
talent: 'auto' | 'skill' | 'burst',
arg: { ele?: ElementKey } & FormulaArg = {},
...extra: Data
): Data {
...extra: TagMapNodeEntries
): TagMapNodeEntries {
const lvl = self.char[talent]
return customShield(
name,
Expand All @@ -114,8 +114,8 @@ export function fixedShield(
percent: number | NumNode,
flat: number | NumNode,
arg: { ele?: ElementKey } & FormulaArg = {},
...extra: Data
): Data {
...extra: TagMapNodeEntries
): TagMapNodeEntries {
return customShield(
name,
arg.ele,
Expand All @@ -128,8 +128,8 @@ export function fixedShield(
export function entriesForChar(
{ ele, weaponType, region }: CharInfo,
{ lvlCurves, ascensionBonus }: CharacterDataGen
): Data {
const specials = new Set(Object.keys(lvlCurves.map(({ key }) => key)))
): TagMapNodeEntries {
const specials = new Set(lvlCurves.map(({ key }) => key))
specials.delete('atk')
specials.delete('def')
specials.delete('hp')
Expand Down
4 changes: 2 additions & 2 deletions libs/gi-formula/src/data/common/dmg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
sum,
sumfrac,
} from '@genshin-optimizer/pando'
import type { Data } from '../util'
import type { TagMapNodeEntries } from '../util'
import {
enemy,
enemyDebuff,
Expand All @@ -24,7 +24,7 @@ export const infusionPrio = {
const infusionTable = priorityTable(infusionPrio),
preRes = enemy.common.preRes

const data: Data = [
const data: TagMapNodeEntries = [
enemyDebuff.common.postRes.add(custom('res', preRes)),
enemyDebuff.common.inDmg.add(
prod(
Expand Down
12 changes: 4 additions & 8 deletions libs/gi-formula/src/data/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import { allElementKeys } from '@genshin-optimizer/consts'
import { max, min, prod, subscript, sum } from '@genshin-optimizer/pando'
import type { Data } from '../util'
import type { TagMapNodeEntries } from '../util'
import { allStatics, percent, reader, self, selfBuff, team } from '../util'
import dmg from './dmg'
import prep from './prep'
import reaction from './reaction'
import { allStats } from '@genshin-optimizer/gi-stats'

const data: Data = [
const data: TagMapNodeEntries = [
...dmg,
...prep,
...reaction,

reader
.withTag({ src: 'iso', et: 'self' })
.reread(reader.withTag({ src: 'custom' })),
reader
.withTag({ src: 'agg', et: 'self' })
.reread(reader.withTag({ src: 'custom' })),
reader.withTag({ src: 'iso', et: 'self' }).reread(reader.src('custom')),
reader.withTag({ src: 'agg', et: 'self' }).reread(reader.src('custom')),

// Final <= Premod <= Base
reader
Expand Down
4 changes: 2 additions & 2 deletions libs/gi-formula/src/data/common/prep.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { cmpEq, dynTag, lookup, prod, sum } from '@genshin-optimizer/pando'
import type { Data } from '../util'
import type { TagMapNodeEntries } from '../util'
import { enemy, percent, self, selfBuff, tagVal } from '../util'

const { ele, amp, cata } = self.prep

const data: Data = [
const data: TagMapNodeEntries = [
// Formulas
// If any `prep` nodes are available, put them in `dynTag` or note them here
selfBuff.formula.dmg.add(
Expand Down
4 changes: 2 additions & 2 deletions libs/gi-formula/src/data/common/reaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
sum,
sumfrac,
} from '@genshin-optimizer/pando'
import type { Data } from '../util'
import type { TagMapNodeEntries } from '../util'
import { percent, self, selfBuff, tag } from '../util'

const transLvlMultis = [
Expand Down Expand Up @@ -312,7 +312,7 @@ function trigger(
trigger(ele, trans, immediateFromEle)
}

const data: Data = [
const data: TagMapNodeEntries = [
selfBuff.reaction.ampBase.add(eleMasMulti(25 / 9, 1400)),
selfBuff.reaction.ampMulti.melt.cryo.add(prod(1.5, ampBase)),
selfBuff.reaction.ampMulti.melt.pyro.add(prod(2.0, ampBase)),
Expand Down
31 changes: 19 additions & 12 deletions libs/gi-formula/src/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@ import {
import artifact from './artifact'
import character from './char'
import common from './common'
import type { Data } from './util'
import { fixedTags, queries, queryTypes, usedNames } from './util'
import type { TagMapNodeEntries } from './util'
import { fixedTags, queryTypes, usedNames, usedQ } from './util'
import weapon from './weapon'

const data: Data = [...common, ...artifact, ...character, ...weapon]
const tags = [
{ category: 'qt', values: [...queryTypes] },
{ category: 'q', values: ['_', ...queries] },
undefined,
...Object.entries(fixedTags).map(([k, v]) => ({ category: k, values: v })),
{ category: 'name', values: [...usedNames] },
const entries: TagMapNodeEntries = [
...common,
...artifact,
...character,
...weapon,
]
const keys = compileTagMapKeys(tags) // TODO: Find optimum tag order
const values = compileTagMapValues(keys, data)
const keys = compileTagMapKeys([
{ category: 'qt', values: queryTypes },
{ category: 'q', values: usedQ },
undefined,
...Object.entries(fixedTags).map(([k, v]) => ({
category: k,
values: new Set(v),
})),
{ category: 'name', values: usedNames },
]) // TODO: Find optimum tag order
const values = compileTagMapValues(keys, entries)

export { keys, values, data }
export { entries, keys, values }
13 changes: 11 additions & 2 deletions libs/gi-formula/src/data/util/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import type { AnyNode, ReRead } from '@genshin-optimizer/pando'
import type {
AnyNode,
ReRead,
TagMapEntries,
TagMapEntry,
} from '@genshin-optimizer/pando'
import type { Tag } from './read'

export * from './listing'
export * from './read'
export * from './sheet'
export * from './tag'
export type Data = { tag: Tag; value: AnyNode | ReRead }[]

/** See `TagMapEntry` */
export type TagMapNodeEntry = TagMapEntry<AnyNode | ReRead, Tag>
/** See `TagMapEntries` */
export type TagMapNodeEntries = TagMapEntries<AnyNode | ReRead, Tag>
1 change: 1 addition & 0 deletions libs/gi-formula/src/data/util/listing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const srcs = [
...allWeaponKeys,
...allArtifactSetKeys,
'art',
'dyn',
'enemy',
'custom',
] as const
Expand Down
Loading
Loading