4c1c0e9ff2
CI / build-and-push (push) Successful in 32s
Replace the single-stage training + flat capability score with a realistic AI development pipeline: pre-training with Chinchilla scaling laws, SFT with specializations, alignment with safety/capability tradeoffs (RLHF/DPO/Constitutional), model families with distillation/fine-tuning/quantization variants, named benchmark suite with compute-costing eval jobs, and segment-specific market quality. Phases 1-6 of the model rework plan: new types, engine rewrite, save migration, training events/risk system, concurrent training, variant creation, benchmark evaluation with leaderboard, and market integration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import type { GameState, AchievementState, AchievementDefinition } from '@ai-tycoon/shared';
|
|
|
|
export interface AchievementTickResult {
|
|
achievements: AchievementState;
|
|
newAchievements: string[];
|
|
}
|
|
|
|
const ERA_INDEX: Record<string, number> = { startup: 0, scaleup: 1, bigtech: 2, agi: 3 };
|
|
|
|
function getFieldValue(state: GameState, field: string): number {
|
|
if (field === 'meta._eraIndex') return ERA_INDEX[state.meta.currentEra] ?? 0;
|
|
if (field === 'meta._deployedModelCount') return state.models.baseModels.filter(m => m.isDeployed).length;
|
|
const parts = field.split('.');
|
|
let current: unknown = state;
|
|
for (const part of parts) {
|
|
if (current == null || typeof current !== 'object') return 0;
|
|
current = (current as Record<string, unknown>)[part];
|
|
}
|
|
return typeof current === 'number' ? current : 0;
|
|
}
|
|
|
|
function checkCondition(state: GameState, def: AchievementDefinition): boolean {
|
|
const value = getFieldValue(state, def.condition.field);
|
|
switch (def.condition.operator) {
|
|
case 'gt': return value > def.condition.value;
|
|
case 'gte': return value >= def.condition.value;
|
|
case 'eq': return value === def.condition.value;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
export function processAchievements(
|
|
state: GameState,
|
|
definitions: AchievementDefinition[],
|
|
): AchievementTickResult {
|
|
if (state.meta.tickCount % 10 !== 0) {
|
|
return { achievements: state.achievements, newAchievements: [] };
|
|
}
|
|
|
|
const unlockedIds = new Set(state.achievements.unlocked.map(a => a.id));
|
|
const newAchievements: string[] = [];
|
|
const unlocked = [...state.achievements.unlocked];
|
|
|
|
for (const def of definitions) {
|
|
if (unlockedIds.has(def.id)) continue;
|
|
if (checkCondition(state, def)) {
|
|
unlocked.push({ id: def.id, unlockedAtTick: state.meta.tickCount });
|
|
newAchievements.push(def.name);
|
|
}
|
|
}
|
|
|
|
return {
|
|
achievements: { ...state.achievements, unlocked },
|
|
newAchievements,
|
|
};
|
|
}
|