merge: 合併 origin/main(M0 cockpit 改名)並整合 companion
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { clamp } from './mood'
|
||||
import type { Affinity } from './types'
|
||||
|
||||
const DAY = 86_400_000
|
||||
|
||||
export const GAIN = 0.01
|
||||
export const DAILY_CAP = 0.05
|
||||
export const LOSS = 0.03
|
||||
const IDLE_GRACE_DAYS = 7
|
||||
const IDLE_HALF_LIFE_DAYS = 30
|
||||
|
||||
// 升階門檻;降階門檻 = 升階門檻 − 0.05,形成遲滯
|
||||
export const UP = [0.3, 0.55, 0.8]
|
||||
export const HYSTERESIS = 0.05
|
||||
|
||||
export const dayKey = (ms: number) => new Date(ms).toISOString().slice(0, 10)
|
||||
|
||||
export const initialAffinity = (now: number): Affinity => ({ value: 0, stage: 0, dayKey: dayKey(now), dayGain: 0, lastSeen: now })
|
||||
|
||||
export function stageFor(value: number, current: number): number {
|
||||
let s = current
|
||||
while (s < UP.length && value >= UP[s]!) s++
|
||||
while (s > 0 && value < UP[s - 1]! - HYSTERESIS) s--
|
||||
return s
|
||||
}
|
||||
|
||||
// 離開超過 7 天後,以 30 天半衰期回到 0
|
||||
export function idleDecay(a: Affinity, now: number): Affinity {
|
||||
const idleDays = (now - a.lastSeen) / DAY
|
||||
if (idleDays <= IDLE_GRACE_DAYS) return a
|
||||
const value = a.value * Math.pow(0.5, (idleDays - IDLE_GRACE_DAYS) / IDLE_HALF_LIFE_DAYS)
|
||||
return { ...a, value, stage: stageFor(value, a.stage) }
|
||||
}
|
||||
|
||||
export function interact(prev: Affinity, kind: 'meaningful' | 'negative', now: number): Affinity {
|
||||
let a = idleDecay(prev, now)
|
||||
const key = dayKey(now)
|
||||
if (a.dayKey !== key) a = { ...a, dayKey: key, dayGain: 0 }
|
||||
let { value, dayGain } = a
|
||||
if (kind === 'meaningful') {
|
||||
const gain = Math.max(0, Math.min(GAIN, DAILY_CAP - dayGain))
|
||||
value += gain
|
||||
dayGain += gain
|
||||
} else {
|
||||
value -= LOSS
|
||||
}
|
||||
value = clamp(value)
|
||||
return { value, dayGain, dayKey: key, lastSeen: now, stage: stageFor(value, a.stage) }
|
||||
}
|
||||
Reference in New Issue
Block a user