Skip to content

Commit

Permalink
adding basic opt targets to ZO
Browse files Browse the repository at this point in the history
  • Loading branch information
frzyc committed Jan 21, 2025
1 parent 4d74491 commit b345b03
Show file tree
Hide file tree
Showing 9 changed files with 382 additions and 55 deletions.
82 changes: 82 additions & 0 deletions libs/zzz/consts/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,45 @@
import { objKeyMap } from '@genshin-optimizer/common/util'
import { allDiscMainStatKeys, allDiscSubStatKeys } from './disc'

export const otherStatKeys = [
// Used by calc, likely will be bundled into pando
'charLvl',
'enemyDef', // Enemy DEF
'enemyRes_', // Enemy Resistance
'enemyResRed_', // Enemy Resistance Reduction
'enemyResIgn_', // Enemy Resistance Ignore
'dmg_', // Bonus DMG

// Other stats
'impact', // flat impact on character
'anomMas', // flat Anomally Mastery on character
'shield_', // Shield Effect
] as const

export const unCondKeys = [
'uncond_hp',
'uncond_def',
'uncond_atk',
'uncond_hp_',
'uncond_def_',
'uncond_atk_',
] as const

export const allStatKeys = Array.from(
new Set([...allDiscMainStatKeys, ...allDiscSubStatKeys, ...otherStatKeys])
)
export type StatKey = (typeof allStatKeys)[number]

const allElementalKeys = [
'electric',
'fire',
'ice',
'frost',
'physical',
'ether',
] as const
export type ElementalKey = (typeof allElementalKeys)[number]

export const allAttributeDamageKeys = [
'electric_dmg_',
'fire_dmg_',
Expand All @@ -20,3 +49,56 @@ export const allAttributeDamageKeys = [
'ether_dmg_',
] as const
export type AttributeDamageKey = (typeof allAttributeDamageKeys)[number]

export const allAnomalyDmgKeys = [
'burn',
'shock',
'corruption',
'shatter',
'assault',
] as const
export type AnomalyDamageKey = (typeof allAnomalyDmgKeys)[number]

export const statKeyTextMap: Partial<Record<string, string>> = {
hp: 'HP',
hp_: 'HP',
atk: 'ATK',
atk_: 'ATK',
def: 'DEF',
def_: 'DEF',
pen: 'PEN',
pen_: 'PEN Ratio',
crit_: 'CRIT Rate',
crit_dmg_: 'CRIT DMG',
enerRegen_: 'Energy Regen',
impact_: 'Impact',
anomMas_: 'Anomaly Mastery',
anomProf: 'Anomaly Proficiency',
...objKeyMap(allAnomalyDmgKeys, (dmg_) => `${dmg_} DMG Bonus`),
dmg_: 'DMG Bonus',
charLvl: 'Character Level',
enemyDef: 'Enemy DEF',
enemyRes_: 'Enemy Resistance',
enemyResRed_: 'Enemy Resistance Reduction',
enemyResIgn_: 'Enemy Resistance Ignore',

uncond_hp: 'Unconditional HP',
uncond_def: 'Unconditional DEF',
uncond_atk: 'Unconditional ATK',
uncond_hp_: 'Unconditional HP%',
uncond_def_: 'Unconditional DEF%',
uncond_atk_: 'Unconditional ATK%',
}

const elementalData: Record<ElementalKey, string> = {
electric: 'Electric',
fire: 'Fire',
ice: 'Ice',
frost: 'Frost',
physical: 'Physical',
ether: 'Ether',
} as const

Object.entries(elementalData).forEach(([e, name]) => {
statKeyTextMap[`${e}_dmg_`] = `${name} DMG Bonus`
})
70 changes: 48 additions & 22 deletions libs/zzz/page-optimize/src/BaseStatCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { CardThemed, NumberInputLazy } from '@genshin-optimizer/common/ui'
import { getUnitStr } from '@genshin-optimizer/common/util'
import type { StatKey } from '@genshin-optimizer/zzz/consts'
import { allAttributeDamageKeys } from '@genshin-optimizer/zzz/consts'
import {
allAttributeDamageKeys,
statKeyTextMap,
unCondKeys,
} from '@genshin-optimizer/zzz/consts'
import type { BaseStats } from '@genshin-optimizer/zzz/solver'
import { CardContent, Stack } from '@mui/material'
const baseKeys = ['hp_base', 'atk_base', 'def_base'] as const
import { Box, CardContent, Typography } from '@mui/material'
const baseKeys = ['charLvl', 'hp_base', 'atk_base', 'def_base'] as const
const statKeys: StatKey[] = [
'hp',
'atk',
Expand All @@ -15,6 +19,13 @@ const statKeys: StatKey[] = [
'crit_',
'crit_dmg_',
...allAttributeDamageKeys,
'dmg_',
] as const
const enemyKeys: StatKey[] = [
'enemyDef',
'enemyRes_',
'enemyResRed_',
'enemyResIgn_',
] as const
export default function BaseStatCard({
baseStats,
Expand All @@ -23,28 +34,43 @@ export default function BaseStatCard({
baseStats: BaseStats
setBaseStats: (baseStats: BaseStats) => void
}) {
const input = (key: string) => (
<NumberInputLazy
key={key}
sx={{ flexGrow: 1 }}
value={baseStats[key] || 0}
onChange={(v) =>
setBaseStats({
...baseStats,
[key]: v,
})
}
inputProps={{ sx: { textAlign: 'right', minWidth: '5em' } }}
InputProps={{
startAdornment: statKeyTextMap[key] ?? key,
endAdornment: getUnitStr(key),
}}
/>
)
return (
<CardThemed>
<CardContent>
<Stack spacing={1}>
{[...baseKeys, ...statKeys].map((key) => (
<NumberInputLazy
key={key}
value={baseStats[key] || 0}
onChange={(v) =>
setBaseStats({
...baseStats,
[key]: v,
})
}
inputProps={{ sx: { textAlign: 'right' } }}
InputProps={{
startAdornment: key,
endAdornment: getUnitStr(key),
}}
/>
))}
</Stack>
<Typography>Character Base Stats</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{baseKeys.map((key) => input(key))}
</Box>
<Typography>Character Stats</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{statKeys.map((key) => input(key))}
</Box>
<Typography>Enemy Stats</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{enemyKeys.map((key) => input(key))}
</Box>
<Typography>Combat Buffs(Unconditonal)</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{unCondKeys.map((key) => input(key))}
</Box>
</CardContent>
</CardThemed>
)
Expand Down
3 changes: 2 additions & 1 deletion libs/zzz/page-optimize/src/BuildsDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
toDecimal,
valueString,
} from '@genshin-optimizer/common/util'
import { statKeyTextMap } from '@genshin-optimizer/zzz/consts'
import { useDatabaseContext, useDisc } from '@genshin-optimizer/zzz/db-ui'
import type { BaseStats, BuildResult } from '@genshin-optimizer/zzz/solver'
import { convertDiscToStats, getSum } from '@genshin-optimizer/zzz/solver'
Expand Down Expand Up @@ -46,7 +47,7 @@ function Build({
<CardContent>
{Object.entries(sum).map(([k, v]) => (
<Typography key={k}>
{k}: {valueString(v, getUnitStr(k))}
{statKeyTextMap[k] ?? k}: {valueString(v, getUnitStr(k))}
</Typography>
))}
<Box display="flex" gap={1}>
Expand Down
88 changes: 66 additions & 22 deletions libs/zzz/page-optimize/src/Optimize.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CardThemed } from '@genshin-optimizer/common/ui'
import { CardThemed, DropdownButton } from '@genshin-optimizer/common/ui'
import { objMap, toDecimal } from '@genshin-optimizer/common/util'
import type { DiscSlotKey } from '@genshin-optimizer/zzz/consts'
import type { ICachedDisc } from '@genshin-optimizer/zzz/db'
Expand All @@ -7,9 +7,14 @@ import type {
BaseStats,
BuildResult,
Constraints,
FormulaKey,
ProgressResult,
} from '@genshin-optimizer/zzz/solver'
import { MAX_BUILDS, Solver } from '@genshin-optimizer/zzz/solver'
import {
allFormulaKeys,
MAX_BUILDS,
Solver,
} from '@genshin-optimizer/zzz/solver'
import CloseIcon from '@mui/icons-material/Close'
import TrendingUpIcon from '@mui/icons-material/TrendingUp'
import {
Expand All @@ -19,6 +24,7 @@ import {
CardHeader,
Divider,
LinearProgress,
MenuItem,
Typography,
} from '@mui/material'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
Expand All @@ -40,7 +46,7 @@ export default function OptimizeWrapper({
const [progress, setProgress] = useState<ProgressResult | undefined>(
undefined
)

const [formulaKey, setFormulaKey] = useState<FormulaKey>(allFormulaKeys[0])
const [constraints, setConstraints] = useState<Constraints>({})
const discsBySlot = useMemo(
() =>
Expand Down Expand Up @@ -84,6 +90,7 @@ export default function OptimizeWrapper({
setOptimizing(true)

const optimizer = new Solver(
formulaKey,
objMap(baseStats, (v, k) => toDecimal(v, k)),
objMap(constraints, (c, k) => ({ ...c, value: toDecimal(c.value, k) })),
discsBySlot,
Expand All @@ -99,7 +106,7 @@ export default function OptimizeWrapper({

setOptimizing(false)
setResults(results)
}, [baseStats, constraints, discsBySlot, numWorkers, setResults])
}, [baseStats, constraints, discsBySlot, formulaKey, numWorkers, setResults])

const onCancel = useCallback(() => {
cancelToken.current()
Expand All @@ -108,30 +115,30 @@ export default function OptimizeWrapper({

return (
<CardThemed>
<CardHeader
title={t('optimize')}
action={
<Box>
<WorkerSelector
numWorkers={numWorkers}
setNumWorkers={setNumWorkers}
/>
<Button
onClick={optimizing ? onCancel : onOptimize}
color={optimizing ? 'error' : 'primary'}
startIcon={optimizing ? <CloseIcon /> : <TrendingUpIcon />}
>
{optimizing ? t('cancel') : t('optimize')}
</Button>
</Box>
}
/>
<CardHeader title={t('optimize')} />
<Divider />
<CardContent>
<StatFilterCard
constraints={constraints}
setConstraints={setConstraints}
/>
<Box sx={{ display: 'flex', gap: 1, mt: 2 }}>
<OptimizeTargetSelector
formulaKey={formulaKey}
setFormulaKey={setFormulaKey}
/>
<WorkerSelector
numWorkers={numWorkers}
setNumWorkers={setNumWorkers}
/>
<Button
onClick={optimizing ? onCancel : onOptimize}
color={optimizing ? 'error' : 'success'}
startIcon={optimizing ? <CloseIcon /> : <TrendingUpIcon />}
>
{optimizing ? t('cancel') : t('optimize')}
</Button>
</Box>
{progress && (
<ProgressIndicator
progress={progress}
Expand Down Expand Up @@ -168,3 +175,40 @@ function ProgressIndicator({
</Box>
)
}
function OptimizeTargetSelector({
formulaKey,
setFormulaKey,
}: {
formulaKey: FormulaKey
setFormulaKey: (key: FormulaKey) => void
}) {
return (
<DropdownButton
title={
<span>
Optimize Target: <strong>{formulaKeyTextMap[formulaKey]}</strong>
</span>
}
sx={{ flexGrow: 1 }}
>
{allFormulaKeys.map((fk) => (
<MenuItem key={fk} onClick={() => setFormulaKey(fk)}>
{formulaKeyTextMap[fk]}
</MenuItem>
))}
</DropdownButton>
)
}
const formulaKeyTextMap: Record<FormulaKey, string> = {
electric_dmg_: 'Eletrical Damage',
fire_dmg_: 'Fire Damage',
ice_dmg_: 'Ice Damage',
frost_dmg_: 'Frost Damage',
physical_dmg_: 'Physical Damage',
ether_dmg_: 'Ether Damage',
burn: 'Burn Anomaly',
shock: 'Shock Anomaly',
corruption: 'Corruption Anomaly',
shatter: 'Shatter Anomaly',
assault: 'Assault Anomaly',
}
2 changes: 2 additions & 0 deletions libs/zzz/page-optimize/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export default function PageDiscs() {
const [builds, setBuilds] = useState<BuildResult[]>([])
// base stats are in percent for displayability
const [baseStats, setBaseStats] = useState<BaseStats>({
charLvl: 60,
enemyDef: 953, // default enemy DEF
crit_: 5,
crit_dmg_: 50,
})
Expand Down
Loading

0 comments on commit b345b03

Please sign in to comment.