Files
fumen-measure-analyze/script/factorize.ts
2026-04-24 13:43:00 +09:00

87 lines
2.8 KiB
TypeScript

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)
};
}