feat(看板娘): 接上全班进度、难度、提示、知识点、排名等数据,说的话更贴每个人
Deploy / deploy (push) Successful in 50s

- 题目页:这节课同班做对的人多就说「全班已经 N 个人做对了」、都卡着就安慰、第一个做对的夸一句;
  通过率不到三成的题错了说「本来就难」、高于七成的说「再看看题」;AI 提示开了没用就提一句;
  做对了还有挑战就问敢不敢;流程图分低、拿 S 各有话
- 常点「太难了」的学生错了换软话;这周交得多、例子跑得少的念一句;卡住却从不举手的劝举手;
  这周要提示多的劝先自己想
- 首页(这节课没要做的时)每次戳随机说一件:知识点差几道升级、周榜差几道超过前一名、
  今天明天的比赛、三天内的新公告;两周以上没来说「好久不见」,只说一回
- 排名页第一名、差前一名几道;成就页差一点的;自学没全对的练一练;专题差最后一道拿奖章
- 运行例子、自己输入、举手也记进 mascot_event(trial、help),GET /mascot/profile
  多给「太难了」次数和这一周交、跑例子、举手、要提示的次数

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-11-03 16:33:35 +08:00
1 parent 81ef4dca6b
commit aa7e0a6eb8
12 files changed
+296 -25

No files matched your search

+24 -1
View File
@@ -83,6 +83,15 @@ export function habitSituation(failure: MascotSituation): MascotSituation | null
}
const HABIT_CHANCE = 0.6
const GENTLE_CHANCE = 0.5
const WEEK_CHANCE = 0.4
/** 点过这么多次「太难了」,错了就别怼了 */
const GENTLE_TOO_HARD = 3
/** 这一周交了这么多次、例子却跑得不到五分之一,才说她「从来不跑例子」 */
const WEEK_SUBMITS_MIN = 10
/** 这一周要了这么多次 AI 提示,就劝先自己想 */
const WEEK_HINTS_MANY = 5
const FAILURES = new Set<MascotSituation>(['problem.wrong', 'problem.compileError', 'problem.runtimeError', 'problem.timeout'])
const TODAY_CHANCE = 0.4
const FAMILIAR_CHANCE = 0.2
/** 点开过这么多次算老熟人 */
@@ -96,7 +105,21 @@ const PRAISE = new Set<MascotSituation>(['problem.accepted', 'problem.firstTry',
export function personalize(guide: MascotGuide): MascotGuide {
const profile = mascotProfile.value
if (!profile) return guide
if (profile.pokes + sessionPokes === 0) return { ...guide, situation: 'first.meet', n: undefined }
if (profile.pokes + sessionPokes === 0) return { ...guide, situation: 'first.meet', n: undefined, vars: undefined }
const situation = guide.situation
// 常点「太难了」的,错了先软着说,不翻老毛病
if (FAILURES.has(situation) && profile.tooHard >= GENTLE_TOO_HARD && Math.random() < GENTLE_CHANCE) return { ...guide, situation: 'gentle.wrong' }
const week = profile.week
if (situation === 'problem.stuck' && week.helps === 0 && Math.random() < WEEK_CHANCE) return { ...guide, situation: 'habit.neverHelp' }
if (situation === 'problem.hintReady' && week.aiHints >= WEEK_HINTS_MANY) return { ...guide, situation: 'habit.aiHintMany', n: week.aiHints }
if (
(situation === 'problem.unsubmitted' || situation === 'problem.samplesFailed') &&
week.submits >= WEEK_SUBMITS_MIN &&
week.trials * 5 < week.submits &&
Math.random() < WEEK_CHANCE
) {
return { ...guide, situation: 'habit.weekNoSamples', n: week.submits }
}
const habit = habitSituation(guide.situation)
if (habit && Math.random() < HABIT_CHANCE) return { ...guide, situation: habit }
if (PRAISE.has(guide.situation) && profile.todaySolved >= TODAY_MIN && Math.random() < TODAY_CHANCE) {