feat: support every song difficulty including Easy and Normal
Publish GitHub Pages output / publish (push) Successful in 41s
Publish GitHub Pages output / publish (push) Successful in 41s
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { difficulties, isDifficulty } from '../data/difficulty.ts';
|
||||
import { calculateExactScore, perfectNoteScoreFromPower } from './score.ts';
|
||||
|
||||
test('모든 악곡의 네 난이도 채보를 불러와 실제 점수를 계산한다', async () => {
|
||||
const catalog = JSON.parse(await readFile(new URL('../data/exact-chart-catalog.json', import.meta.url), 'utf8'));
|
||||
const bySong = new Map<string, Set<string>>();
|
||||
for (const row of catalog.charts) {
|
||||
assert.ok(isDifficulty(row.difficulty));
|
||||
const seen = bySong.get(row.songId) ?? new Set<string>();
|
||||
assert.ok(!seen.has(row.difficulty), `${row.songId}: 중복 난이도`);
|
||||
seen.add(row.difficulty);
|
||||
bySong.set(row.songId, seen);
|
||||
const chart = JSON.parse(await readFile(new URL(`../../../static${row.path}`, import.meta.url), 'utf8'));
|
||||
assert.equal(chart.songId, row.songId);
|
||||
assert.equal(chart.difficulty, row.difficulty);
|
||||
assert.equal(chart.notes.length, row.totalNotes);
|
||||
assert.ok(chart.notes.length > 0);
|
||||
// 튜토리얼용 짧은 곡은 스페셜 구간이 두 개뿐이다.
|
||||
assert.equal(chart.specialStartSeconds.length, row.songId === 'm9999' ? 2 : 5);
|
||||
assert.equal(chart.scoreCalibrationSource, 'formula-v1');
|
||||
const score = calculateExactScore([], {}, chart, {
|
||||
perfectNoteScore: perfectNoteScoreFromPower(100000, chart.scoreRatio)
|
||||
});
|
||||
assert.ok(Number.isFinite(score.expectedScore) && score.expectedScore > 0, `${row.songId}.${row.difficulty}`);
|
||||
}
|
||||
assert.ok(bySong.size > 0);
|
||||
for (const [songId, actual] of bySong) assert.deepEqual(actual, new Set(difficulties), songId);
|
||||
});
|
||||
@@ -41,6 +41,13 @@ test('성장 상태를 공유하는 기록 백업을 손실 없이 읽고 잘못
|
||||
const parsed = parseAnalysisArchive(JSON.stringify(archive));
|
||||
assert.equal(parsed.records.length, 2); assert.equal(parsed.snapshots.length, 1);
|
||||
assert.deepEqual(parsed.snapshots[0].growth, growth);
|
||||
for (const difficulty of ['easy', 'normal', 'hard', 'expert']) {
|
||||
record.settings.difficulty = difficulty;
|
||||
assert.equal(parseAnalysisArchive(JSON.stringify(archive)).records[0].settings.difficulty, difficulty);
|
||||
}
|
||||
record.settings.difficulty = 'invalid';
|
||||
assert.throws(() => parseAnalysisArchive(JSON.stringify(archive)));
|
||||
record.settings.difficulty = 'expert';
|
||||
record.settings.awakenings[0] = 8;
|
||||
assert.throws(() => parseAnalysisArchive(JSON.stringify(archive)));
|
||||
});
|
||||
|
||||
@@ -31,3 +31,14 @@ test('고점 순위와 상위 3곡 합계는 동일 곡의 난이도를 중복
|
||||
assert.equal(leaderRating([]), 0);
|
||||
assert.equal(results[0].theoreticalMaxScore, 5001);
|
||||
});
|
||||
|
||||
test('전체 난이도 추천은 Easy와 Normal을 포함하고 곡별 최고점만 합산한다', () => {
|
||||
const charts = ['easy', 'normal', 'hard', 'expert'].map((difficulty, index) => ({
|
||||
songId: 'song', title: 'Song', difficulty, singerCharacterIds: ['leader'],
|
||||
theoreticalMaxScore: 20000 - index * 5000, expectedScore: 1000
|
||||
}));
|
||||
assert.deepEqual(leaderRatingCharts(charts, 'leader', 'all', Date.now()), charts);
|
||||
assert.deepEqual(leaderRatingCharts(charts, 'leader', 'normal', Date.now()), [charts[1]]);
|
||||
assert.equal(rankSongs(charts)[0].difficulty, 'easy');
|
||||
assert.equal(leaderRating(charts), 4);
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isDifficulty } from '../data/difficulty.ts';
|
||||
import { releasedSongCharts } from '../data/song-release.ts';
|
||||
|
||||
export type RatingChart = {
|
||||
@@ -17,7 +18,7 @@ export function songRating(score: number): number {
|
||||
export function leaderRatingCharts<T extends RatingChart>(charts: readonly T[], leaderId: string, difficulty: string, now: number): T[] {
|
||||
return releasedSongCharts(charts, now).filter((chart) =>
|
||||
Boolean(leaderId) && chart.singerCharacterIds?.includes(leaderId) &&
|
||||
(difficulty === 'both' ? chart.difficulty === 'hard' || chart.difficulty === 'expert' : chart.difficulty === difficulty));
|
||||
(difficulty === 'all' ? isDifficulty(chart.difficulty) : difficulty === 'both' ? chart.difficulty === 'hard' || chart.difficulty === 'expert' : chart.difficulty === difficulty));
|
||||
}
|
||||
|
||||
export type SongRatingScore = {
|
||||
|
||||
@@ -50,7 +50,7 @@ test('공식 적용 카탈로그와 실제 채보가 같은 분모 및 환산값
|
||||
assert.equal(chart.notes.length, ref.fullComboNoteCount);
|
||||
formulaCount += 1;
|
||||
}
|
||||
assert.equal(formulaCount, 388);
|
||||
assert.equal(formulaCount, catalog.charts.length);
|
||||
});
|
||||
|
||||
test('잘못된 분모와 난이도로 공식 환산값을 만들지 않는다', () => {
|
||||
|
||||
Reference in New Issue
Block a user