import { Bar, Course } from 'tja-parser'; export interface Factors { physical_density: number; stamina_requirement: number; pattern_complexity: number; rhythmic_complexity: number; reading_gimmick: number; } export namespace Factor { export function getAllNotes(course: Course): any[] { const notes: any[] = []; for (const group of course.noteGroups) { if (group instanceof Bar) { notes.push(...group.getNotes()); } } return notes; } export function getPhysicalDensity(course: Course): number { const notes = getAllNotes(course); if (notes.length === 0) return 0; const bars = course.noteGroups.length; return notes.length / (bars || 1); } export function getStaminaRequirement(course: Course): number { const notes = getAllNotes(course); let maxStream = 0; let currentStream = 0; for (const note of notes) { if (note.type !== '0') { currentStream++; } else { maxStream = Math.max(maxStream, currentStream); currentStream = 0; } } return Math.max(maxStream, currentStream) / 100; } export function getPatternComplexity(course: Course): number { const notes = getAllNotes(course).filter(n => n.type === '1' || n.type === '2'); let transitions = 0; for (let i = 1; i < notes.length; i++) { if (notes[i].type !== notes[i-1].type) { transitions++; } } return notes.length > 0 ? transitions / notes.length : 0; } export function getRhythmicComplexity(course: Course): number { let complexNotes = 0; const allNotes = getAllNotes(course); for (const group of course.noteGroups) { if (group instanceof Bar) { const division = group.getNotes().length; if (division % 4 !== 0 || division > 16) { complexNotes += division; } } } return allNotes.length > 0 ? complexNotes / allNotes.length : 0; } export function getReadingGimmick(course: Course): number { // BPM 변화나 Scroll 변화 빈도 측정 // tja-parser의 구조에 따라 구현 (여기서는 placeholder) return 0; } } export function factorize(course: Course): Factors { return { physical_density: Factor.getPhysicalDensity(course), stamina_requirement: Factor.getStaminaRequirement(course), pattern_complexity: Factor.getPatternComplexity(course), rhythmic_complexity: Factor.getRhythmicComplexity(course), reading_gimmick: Factor.getReadingGimmick(course) }; }